下面我将提供几个不同的 C++ 示例,分别测试以下场景:
- 单个机器多个进程读取共享文件,锁是否有效
- 一个机器写入共享文件,另一个机器同时读取共享文件,锁是否有效
- 多个机器同时读取共享文件,锁是否有效
- 一个机器同时多个接口写入共享文件,锁是否有效
每个场景都依赖于 POSIX 文件锁(fcntl())来管理文件的读写锁。锁在 NFS 文件系统上通常能确保数据的正确同步,但多个机器访问时,网络延迟和 NFS 配置可能会影响锁的行为,因此要注意环境配置。
1. 单个机器多个进程读取共享文件,锁是否有效
这个代码验证了在同一台机器上,多个进程是否能正确地读取文件并获得锁。
cpp
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstring>
#include <errno.h>
#define FILE_PATH "/mnt/nfs/myfile.txt"
void acquire_read_lock(int fd) {
struct flock lock;
lock.l_type = F_RDLCK; // 读锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "读锁加锁失败: " << strerror(errno) << std::endl;
exit(1);
}
std::cout << "获得读锁" << std::endl;
}
void release_lock(int fd) {
struct flock lock;
lock.l_type = F_UNLCK; // 释放锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "释放锁失败: " << strerror(errno) << std::endl;
}
std::cout << "锁已释放" << std::endl;
}
int main() {
int fd = open(FILE_PATH, O_RDWR | O_CREAT, 0666);
if (fd == -1) {
std::cerr << "文件打开失败: " << strerror(errno) << std::endl;
return 1;
}
// 创建多个进程来模拟并发读取
pid_t pid = fork();
if (pid == 0) {
acquire_read_lock(fd);
std::cout << "子进程 1 正在读取文件..." << std::endl;
sleep(5);
release_lock(fd);
exit(0);
}
pid = fork();
if (pid == 0) {
acquire_read_lock(fd);
std::cout << "子进程 2 正在读取文件..." << std::endl;
sleep(5);
release_lock(fd);
exit(0);
}
wait(NULL);
wait(NULL);
close(fd);
return 0;
}
2. 一个机器写入共享文件,另一个机器同时读取共享文件,锁是否有效
在这个场景中,模拟一台机器进行写入,另一台机器进行读取。需要在不同机器上运行这个代码。
写入机器:
cpp
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <errno.h>
#define FILE_PATH "/mnt/nfs/myfile.txt"
void acquire_write_lock(int fd) {
struct flock lock;
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "写锁加锁失败: " << strerror(errno) << std::endl;
exit(1);
}
std::cout << "获得写锁" << std::endl;
}
void release_lock(int fd) {
struct flock lock;
lock.l_type = F_UNLCK; // 释放锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "释放锁失败: " << strerror(errno) << std::endl;
}
std::cout << "锁已释放" << std::endl;
}
int main() {
int fd = open(FILE_PATH, O_RDWR | O_CREAT, 0666);
if (fd == -1) {
std::cerr << "文件打开失败: " << strerror(errno) << std::endl;
return 1;
}
acquire_write_lock(fd);
std::cout << "写入操作进行中..." << std::endl;
sleep(5); // 模拟写入操作
release_lock(fd);
close(fd);
return 0;
}
读取机器(同上,使用第一个示例)。
3. 多个机器同时读取共享文件,锁是否有效
在这个场景中,多个机器同时进行读取文件的操作,可以在不同机器上运行第一个示例。NFS 文件系统通常允许多个进程同时读取文件,只要它们持有读锁时不会相互干扰。
4. 一个机器同时多个接口写入共享文件,锁是否有效
这个场景模拟了在同一台机器上,通过多个进程进行写入操作,并验证锁是否有效。使用与第二个场景类似的代码,但通过多个进程进行并发写入。
cpp
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <errno.h>
#include <sys/wait.h>
#define FILE_PATH "/mnt/nfs/myfile.txt"
void acquire_write_lock(int fd) {
struct flock lock;
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "写锁加锁失败: " << strerror(errno) << std::endl;
exit(1);
}
std::cout << "获得写锁" << std::endl;
}
void release_lock(int fd) {
struct flock lock;
lock.l_type = F_UNLCK; // 释放锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fd, F_SETLK, &lock) == -1) {
std::cerr << "释放锁失败: " << strerror(errno) << std::endl;
}
std::cout << "锁已释放" << std::endl;
}
int main() {
int fd = open(FILE_PATH, O_RDWR | O_CREAT, 0666);
if (fd == -1) {
std::cerr << "文件打开失败: " << strerror(errno) << std::endl;
return 1;
}
pid_t pid1 = fork();
if (pid1 == 0) {
acquire_write_lock(fd);
std::cout << "子进程 1 正在写入文件..." << std::endl;
sleep(5);
release_lock(fd);
exit(0);
}
pid_t pid2 = fork();
if (pid2 == 0) {
acquire_write_lock(fd);
std::cout << "子进程 2 正在写入文件..." << std::endl;
sleep(5);
release_lock(fd);
exit(0);
}
wait(NULL);
wait(NULL);
close(fd);
return 0;
}
g++ -o file_lock_demo file_lock_demo.cpp
./file_lock_demo
注意事项:
- 需要在 NFS 配置中确保锁机制开启,并且文件系统配置正确。
- 测试时,建议在不同的机器上执行这些进程,尤其是在写入和读取操作之间的锁竞争。
- 为了确保锁机制的有效性,确保使用的 NFS 服务器支持锁定(如 lockd 服务必须启动)。
这些代码分别模拟了不同机器和进程间的锁竞争,通过加锁机制保证了文件的并发访问正确性。运行这些代码时,确保在 NFS 环境中进行测试。