文件锁实现进程间同步

时间:2022-06-24 10:08:00

文件锁实现进程间同步
(APUE学习笔记)

 

  APUE第12章讲述了文件锁(所谓的记录锁),一个很直接的用途就是实现无亲缘关系进程之间的同步.事实上,文件锁的开发先于其他诸多IPC,我要学习的实际上是一个很古老的技术.
  下面是一个简单的实现,我会一步步分析.

 

<lock.c>:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#define LOCK_FILE ".filelock.file"
#define write_lock(fd, offset, whence, len) /
         lock(fd, F_SETLK, F_WRLCK, offset, whence, len)
#define un_lock(fd, offset, whence, len) /
         lock(fd, F_SETLK, F_UNLCK, offset, whence, len)

#define is_writelock(fd, offset, whence, len) /
         lock_test(fd, F_WRLCK, offset, whence, len)


int lock(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
  struct flock lock;

  lock.l_type = type;
  lock.l_start = offset;
  lock.l_whence = whence;
  lock.l_len = len;
  return(fcntl(fd, cmd, &lock));
}


pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
  struct flock lock;

  lock.l_type = type;
  lock.l_start = offset;
  lock.l_whence = whence;
  lock.l_len = len;

  if (fcntl(fd, F_GETLK, &lock) < 0)
        return -1;

  if (lock.l_type == F_UNLCK)
    return 0;
  else
  return lock.l_pid;
}

 

/*
locktest和lock不是原子的,所以该检测不能保证lock一定成功,提供该函数的原因是,当lock失败时,需要locktest确定哪个进程已经占有了锁
*/
pid_t locktest(int fd)
{
    return(is_writelock(fd, 0, SEEK_SET, 0));
}

 

/*
全文写锁
*/
int lock(int fd)
{
    return(write_lock(fd, 0, SEEK_SET, 0));
}

 

int unlock(int fd)
{
    int rtn;   
    rtn = un_lock(fd, 0, SEEK_SET, 0);
    return rtn;
}

int lock_close(int fd)
{
    return(close(fd));
}

 

测试程序A:
int main()
{
static int lock_fd;
int pid;
/*
程序A先运行,所以需要创建文件
*/
lock_fd = open(LOCK_FILE,O_WRONLY | O_CREAT | O_TRUNC, 0777);

whild(1) {

 

/*get lock*/
if(lock(lock_fd) < 0) {
pid = locktest(lock_fd);
if( pid > 0)
printf("lock owned by process %d/n", pid );
continue;
}

 

/*critical area*/
printf("A get lock/n");
sleep(2);

 

/*release lock*/
unlock(lock_fd);
lock_close(lock_fd);
return;
}
}

 

测试程序B:
int main()
{
static int lock_fd;
int pid;
lock_fd = open(LOCK_FILE,O_WRONLY, 0777);

whild(1) {

/*get lock*/
if(lock(lock_fd) < 0) {
pid = locktest(lock_fd);
if( pid > 0)
printf("lock owned by process %d/n", pid );
continue;
}

 

/*critical area */
printf("B get lock/n");

 

/*release lock*/
unlock(lock_fd);
lock_close(lock_fd);
return;
}
}

首先运行程序A,然后运行程序B.可以发现程序B一定是在A之后打印信息.不过这个例子更像是一个临界区.