Linux进程锁方案(内附代码封装)

1)互斥锁

多进程之间同步可以用互斥锁进行实现,默认情况下,互斥锁的属性是在一个进程的多线程使用的。

多进程因为分开之后内存是相对独立的,所以要实现进程间互斥锁,必须要把互斥锁放在共享内存里使用,在 pthread_mutex_init 初始化之前,修改其属性为进程间共享,即设置互斥锁的属性为PTHREAD_PROCESS_SHARED。

但是,如果某个进程在获得了锁之后崩溃并且未释放锁,则其他进程会阻塞造成死锁,但是文件锁,则会自动释放该锁。

2) 文件锁

借助 fcntl 函数来实现文件锁,可以用来对有亲缘或无亲缘关系的进程进行文件读与写的同步。

当一个进程正在读或修改文件或文件的某个部分时,它可以阻止其他进程修改同一文件。

fcntl函数:int fcntl(int fd, int cmd ,struct flock* lock);

应包含头文件: #include

第一个参数fd:文件操作。如,int fd = open(FILE_PATH, O_RDWR | O_CREAT, FILE_MODE);

注意的是:读锁要给读权限,写锁要给写权限。

第二个参数cmd:fcntl函数功能依据cmd的值的不同而不同,与文件锁相关的有:

F_SETLK:获取(l_type为F_RDLCK或F_WRLCK)或释放由lock指向flock结构所描述的锁,如果无法获取锁时,该函数会立即返回一个EACCESS或EAGAIN错误,而不会阻塞。

F_SETLKW:以阻塞方式给文件上锁,当希望设置的锁因为其他锁而被阻止设置时,该命令会等待相冲突的锁被释放。

F_GETLK:主要用来检测是否有某个已存在锁会妨碍将新锁授予调用进程,如果没有这样的锁,lock所指向的flock结构的l_type成员就会被置成F_UNLCK,否则已存在的锁的信息将会写入lock所指向的flock结构中。

这里需要注意的是,用F_GETLK测试能否建立一把锁,然后接着用F_SETLK或F_SETLKW企图建立一把锁,由于这两者不是一个原子操作,所以不能保证两次fcntl之间不会有另外一个进程插入并建立一把相关的锁,从而使一开始的测试情况无效。所以一般不希望上锁时阻塞,会直接通过调用F_SETLK,并对返回结果进行测试,以判断是否成功建立所要求的锁。

第三个参数指向一个struct flock *lock的结构体。

struct flock
{
    short_l_type;    // 锁的类型
    short_l_whence;  // 加锁区域的起始位置
    off_t_l_start;   // 加锁的起始偏移
    off_t_l_len;     // 上锁字节
    pid_t_l_pid;     // 锁的属主进程ID
};

short_l_type: 用来指定设置共享锁(F_RDLCK,读锁)、互斥锁(F_WDLCK,写锁)、解锁(F_UNLCK);

l_whence,l_start,l_len三个变量来确定给文件上锁的区域,当对整个文件上锁时,l_whence,l_start,l_len都设为0;

pid_t_l_pid: 当前锁进程ID,只在获取文件锁命令F_GETLK时起作用。

示例代码:

void lock_init(flock *lock, short type, short whence, off_t start, off_t len) {
    if (lock == nullptr) {
        return;
    }
    lock->l_type = type;
    lock->l_whence = whence;
    lock->l_start = start;
    lock->l_len = len;
}
 
int readw_lock(int fd) {
    if (fd < 0) {
        return -1;
    }
    struct flock lock;
    lock_init(&lock, F_RDLCK, SEEK_SET, 0, 0);
    if (fcntl(fd, F_SETLK, &lock) != 0) {
        return -1;
    }
    return 0;
}
 
int writew_lock(int fd) {
    if (fd < 0) {
        return -1;
    }
    struct flock lock;
    lock_init(&lock, F_WRLCK, SEEK_SET, 0, 0);
    if (fcntl(fd, F_SETLKW, &lock) != 0) {
        return -1;
    }
    return 0;
}
 
int unlock(int fd) {
    if (fd < 0) {
        return -1;
    }
    struct flock lock;
    lock_init(&lock, F_UNLCK, SEEK_SET, 0, 0);
    if (fcntl(fd, F_SETLKW, &lock) != 0) {
        return -1;
    }
    return 0;
}
 
pid_t lock_test(int fd, short type, short whence, off_t start, off_t len) {
    flock lock;
    lock_init(&lock, type, whence, start, len);
    if (fcntl(fd, F_GETLK, &lock) == -1) {
        return -1;
    }
    if(lock.l_type == F_UNLCK)
        return 0;
    return lock.l_pid;
}
​
​
int main() {  
    int fd = open(FILE_PATH, O_RDWR | O_CREAT, FILE_MODE);
    writew_lock(fd);
 
    cout<

你可能感兴趣的:(C++,linux,c++,多进程,锁)