进程同步之记录锁fcntl

函数原型:

int fcntl(int fd, int cmd);  

int fcntl(int fd, int cmd, long arg);  

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

1、fcntl的五种功能

   根据操作类型cmd的不同fcntl有不同的功能:

     F_DUPFD 返回新的文件描述符 
     F_GETFD  返回文件描述符标志 
     F_GETFL  返回文件状态标志 
     F_GETOWN 进程ID或进程组ID 
     All other commands  返回0 
记录锁功能:
      int fcntl(int fd, int cmd, struct flock *lock);
    cmd = F_GETLK,测试能否建立一把锁 
    cmd = F_SETLK,设置锁 
    cmd = F_SETLKW, 阻塞设置一把锁 
struct flock {  
      short l_type;    /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */  
      short l_whence;  /* 加锁的起始位置:SEEK_SET, SEEK_CUR, SEEK_END */  
      off_t l_start;   /* 加锁的起始偏移,相对于l_whence */  
      off_t l_len;     /* 上锁的字节数,如果为0,表示从偏移处一直到文件的末尾*/  
      pid_t l_pid;     /* 已经占用锁的PID(只对F_GETLK 命令有效) */  
      /*...*/  
};  

2、记录锁的使用

记录锁和读写锁一样也有两种锁:共享读锁(F_RDLCK)和独占写锁(F_WRLCK)。

  • 文件给定字节区间,多个进程可以有一把共享读锁,即允许多个进程以读模式访问该字节区;
  • 文件给定字节区间,只能有一个进程有一把独占写锁,即只允许有一个进程已写模式访问该字节区;
  • 文件给定字节区间,如果有一把或多把读锁,不能在该字节区再加写锁,同样,如果有一把写锁,不能再该字节区再加任何读写锁。
  • 加锁时,该进程必须对该文件有相应的文件访问权限,即加读锁,该文件必须是读打开,加写锁时,该文件必须是写打开。

3、记录锁的继承和释放规则

  • 当一个进程终止时,它所建立的记录锁将全部释放;
  • 当关闭一个文件描述符时,则进程通过该文件描述符引用的该文件上的任何一把锁都将被释放。
  • fork产生的子进程不继承父进程所设置的锁。
  • 同一个进程可以重复对同一个文件区间加锁,后加的锁将覆盖前面加的锁。
  • 执行exec后,新程序可以继承原执行程序的锁

4、程序

//初始化flock

  void lock_init(flock *lock, short type, short whence, off_t start, off_t len)

{
    if (lock == NULL)
        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_SETLKW, &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;
}
//测试锁能否建立,不存在返回0,返回存在锁的进程ID。
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);  //以读写的方式打开一个文件
  
    if (fork() == 0)  
    {  
        int fd_1 = open(FILE_PATH, O_RDWR | O_CREAT, FILE_MODE);  
  
        readw_lock(fd_1);  //子进程加读锁
        cout<<"child get read lock..."<<endl;  
  
        sleep(3);  
  
        close(fd_1);  
        cout<<"close the file descriptor..."<<endl;  
  
        pause();  
    }  
  
    sleep(1);  
  
    writew_lock(fd);  //父进程加写锁
    cout<<"parent get write lock..."<<endl;  
    unlock(fd);  
  
    return 0;  
}  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值