进程同步:文件读写锁

1.历史由来

早期UNIX系统并不支持多用户,多进程的文件支持功能(没有良好的锁机制)。商用系统无法使用这样的系统实现数据库系统,因此逐渐开发出文件锁功能

2. posix:fcntl

读写锁的基本要求
在这里插入图片描述
接口:

fcntl(int fd,int cmd,.........);
  参数:fd:文件描述符

        cmd:
        F_GETLK:测试能否加锁
        F_SETLK:对文件加锁,则立即出错返回
        F_SETLKW:对文件加锁,不能加则阻塞
       F_SETLK (struct flock *)
              Acquire  a  lock  (when  l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is
              F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len fields of lock.   If
              a  conflicting  lock  is held by another process, this call returns -1 and sets errno to
              EACCES or EAGAIN.  (The error returned in this case differs across  implementations,  so
              POSIX requires a portable application to check for both errors.)

       F_SETLKW (struct flock *)
              As  for  F_SETLK, but if a conflicting lock is held on the file, then wait for that lock
              to be released.  If a signal is caught while waiting, then the call is  interrupted  and
              (after  the  signal  handler has returned) returns immediately (with return value -1 and
              errno set to EINTR; see signal(7)).

       F_GETLK (struct flock *)
              On input to this call, lock describes a lock we would like to place on the file.  If the
              lock  could  be  placed,  fcntl() does not actually place it, but returns F_UNLCK in the
              l_type field of lock and leaves the other fields of the structure unchanged.

              If one or more incompatible locks would prevent this lock  being  placed,  then  fcntl()
              returns  details  about  one  of those locks in the l_type, l_whence, l_start, and l_len
              fields of lock.  If the conflicting lock is a  traditional  (process-associated)  record
              lock,  then  the l_pid field is set to the PID of the process holding that lock.  If the
              conflicting lock is an open file description lock, then l_pid is set to -1.   Note  that
              the returned information may already be out of date by the time the caller inspects it.


		   第三个参数为 strcuct flock 类型的结构体
		   struct flock {
           ...
           short l_type;    /* Type of lock: F_RDLCK,
                               F_WRLCK, F_UNLCK */
           short l_whence;  /* How to interpret l_start:
                               SEEK_SET, SEEK_CUR, SEEK_END */
           off_t l_start;   /* Starting offset for lock */
           off_t l_len;     /* Number of bytes to lock */
           pid_t l_pid;     /* PID of process blocking our lock
                               (set by F_GETLK and F_OFD_GETLK) */
           ...
       };

2.1 加读锁

struct flock read_lock;
read_lock.l_type = F_RDLCK;
read_lock.l_whence = SEEK_SET;
read_lock.l_start = 0;
read_lock.l_len = 10;

/阻塞版本/
fcntl(fd,F_SETLKW,&read_lock);

/非阻塞版本/
fcntl(fd,F_SETLK ,&read_lock);

/测试pid能否成功加锁/
fcntl(fd,F_GETLK ,&read_lock);

2.2 加写锁

struct flock read_lock;
read_lock.l_type = F_WRLCK;
read_lock.l_whence = SEEK_SET;
read_lock.l_start = 0;
read_lock.l_len = 10;
fcntl(fd,F_SETLKW,&read_lock);

2.3 释放锁

struct flock read_lock;
read_lock.l_type = F_UNLCK ;
read_lock.l_whence = SEEK_SET;
read_lock.l_start = 0;
read_lock.l_len = 10;
fcntl(fd,F_SETLKW,&read_lock);