linux文件锁学习01

来源:互联网 发布:集思宝a5软件 编辑:程序博客网 时间:2024/06/05 17:43

unix下3中对文件加锁的函数:

     lockf:适用于freeBSD系统

     flock:适用于linux系统

     fcntl:使用标准POIX ,可移植到任何标准系统上


区别:

1.flock只能加全局fcntl可以加全局也可以加局部

2.当一个程用flock一个文件加锁时,用另一个程再给这个文件加,它会阻塞或者也可以返回加(可以自己置)

3.当一个程用fcntl一个文件加锁时,用另一个程去或写文件取加的信息,然后在给这个文件加

3.一个文件加fcntl的独占后,再给这个文件加flock的独占,其会入阻塞状

4.一个文件加flock的独占后,用fcntl信息取不到,再用fcntl仍然可以文件加



linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态。

                    文件锁包括建议性锁和强制性的锁。建议性的,顾名思义,相对温柔一些,在对文件进行锁操作时,会检测是否已经有锁存在,并且尊重已有的锁。在一般的情况下,内核和系统都不使用建议锁。强制性的锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他进程对其进行读写操作。采取强制性的锁对性能的影响很大,每次进行读写操作都必须检查是否有锁存在。


--------------------------------------我是分割线------------------------------------------------

  #include <unistdh.>

        int lockf(fd,cmd,size)

        int fd,cmd;

        long size;

 

个方法定文件而言是最简单的。



其中fd文件的handle number 

cmd 所要使用lockf的功能指定,

size則是个功能所要影响的范大小。


    cmd 个参数要代什么的数呢?其unistd.h中也已有以下的定,使用時只要依照所需代入即可:

        #define F_ULOCK 0   /* Unlock a previously locked section */

        #define F_LOCK  1   /* lock a section for exclusive use */

        #define F_TLOCK 2   /* test and lock a section(non-blocking) */

        #define F_TEST  3   /* test section for other process' locks */

    其中F_TEST并没有lock的功能,其主要目的只是在测试文件是否正被其它 process

住而已,当已lockf 返回-1,否則返回

F_LOCKF_TLOCK 的功能也是将文件住,不同之在于如果个文件原先已被其它process F_LOCKblock 住,并等候此文件直至被解除止,至于F_TLOCK 并不会将自己 block

住,而会上返回-1,至于F_TLOCK 等不等于下列程序呢?

        while (lockf(fd,F_TEST,0L)==-1) {}

        lockf(fd,F_LOCK,0L);

    果当然是不等于了!因为这就必critical section问题了!当然,于一个单纯的系而言,F_LOCK便可以达到目的,但于大系而言,由于预测的因素,如果某process 沒有把文件unlock使用F_LOCK便将因等不到文件可以上而使整个系陷入starvation,這是程序审计者必需先考清楚的风险

 

    那么lockf 的最后一个参数size又要如何使用呢?其size指的就是从文件目前的取位置开始,要往前或往后多少位置做lockunlock作,而假若是要整个文件做lockunlock并不需要特別去量size大小,只要直接即可,lockf 便会知道所要影响的范围为整个文件了!



---------------------------------我是分割线---------------------------------------------
flock主要三种操作类型:
     LOCK_SH,共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
     LOCK_EX,排他锁,同时只允许一个进程使用,常被用作写锁;
     LOCK_UN,释放锁;

进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用flock的时候,采用LOCK_NB参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误,errno错误码为EWOULDBLOCK。即提供两种工作模式:阻塞与非阻塞类型。

服务会阻塞等待直到锁被释放:
flock(lockfd,LOCK_EX)
服务会返回错误发现文件已经被锁住时:
ret  = flock(lockfd,LOCK_EX|LOCK_NB)
同时ret = -1, errno = EWOULDBLOCK 

flock锁的释放非常具有特色,即可调用LOCK_UN参数来释放文件锁,也可以通过关闭fd的方式来释放文件锁(flock的第一个参数是fd),意味着flock会随着进程的关闭而被自动释放掉。同时由于damon进程生成时会继承fd。故此方法有一定的局限性。


    #define FILE_NAME "/tmp/filelock"      #include <stdio.h>      #include <unistd.h>      #include <sys/file.h>      int main(int argc , char *agvv[])      {          int fd;          fd = open(FILE_NAME,O_CREAT|O_RDWR,0666);          if( fd == -1)              return -1;          int ret = flock(fd,LOCK_EX|LOCK_NB);          if(ret == 0)          {              printf("first run!\n");              sleep(10);          }else{              printf("already run!\n");          }                return 0;      }

-------------------------------------------我是分割线------------------------------------------

二.fcntl()函数格式

所需头文件:

#include<sys/types.h>,

#include<unistd.h>,

include<fcntl.h>

函数原型:

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

函数参数:

fd:文件描述符

cmd:

 F_DUPFD:复制文件描述符
 F_GETFD:获得fd的close-on-exec标志,若标志未设置,则文件经过exec函数之后仍保持打开状态。
 F_SETFD:设置close-on-exec标志,该标志以参数arg的FD_CLOEXEC位决定。
 F_GETFL:得到open设置的标志
 F_SETFL:改变open设置的标志
 F_GETFK:根据lock描述,决定是否上文件锁
 F_SETFK:设置lock描述的文件锁
 F_SETLKW:这是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果存在其它锁,则调用进程睡眠;如果捕捉到信号则睡眠中断
 F_GETOWN:检索将收到SIGIO和SIGURG信号的进程号或进程组号
 F_SETOWN:设置进程号或进程组号

lock:结构为flock,记录锁的具体状态

struct flock
{
   short l_type;
   off_t l_start;
   short l_whence;
   off_t l_len;
   pid_t l_pid;
}

Lock结构变量取值:

l_type:F_RDLCK:读取锁(共享锁)
       F_WRLCK:写入锁(排斥锁)
       F_UNLCK:解锁
l_start:相对位移量(字节)
l_whence:相对位移量的起点(同lseek的whence):
        SEEK_SET:当前位置为文件开头,新位置为偏移量的大小
        SEEK_CUR:当前位置为文件指针位置,新位置为当前位置加上偏移量
        SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量大小
l_len:加锁区域长度

l_pid是加锁进程的进程id,l_pid不需要指定

返回值 成功返回依赖于cmd的值,若有错误则返回-1,错误原因存于errno.

小技巧:为了锁定整个文件,通常的做法是将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0
二.fcntl()函数使用实例

/*************************************************************************   文件名:flock.c*   文件描述:使用文件锁检测进程中是否唯一实例*原  理:每次进程启动的时候,对文件获取文件锁,下一次检测文件锁是否获取到,得不到就直接退出*创建人: SJW, 2015年10月08日*   版本号:1.0*   修改记录:************************************************************************/#define FILE_NAME "/tmp/filelock"  #include <stdio.h>  #include <unistd.h>  #include <sys/file.h>  /*================================================================ * 函    数 :is_single_f * 参    数1:需要存储文件锁的位置 * 功能描述:对指定位置文件获取文件锁,使用的是建议锁,锁定的是全部文件 * 返 回 值:成功0,失败-1 * 抛出异常: ================================================================*/int is_single_f(char * process_name){int fd;      fd = open(process_name,O_CREAT|O_RDWR,0666);      if( fd == -1)          return -1;      int ret = flock(fd,LOCK_EX|LOCK_NB);      if(ret == 0)      {          printf("first run!\n");          sleep(10);        return 0;      }else{          printf("already run!\n");         return -1;     } return 0;}/*================================================================ * 函    数 :Lockfile * 参    数1:需要存储文件锁的位置 * 功能描述:对指定位置文件获取文件锁,使用的是建议锁,锁定的是指定位置字符串 * 返 回 值:成功0,失败-1 * 抛出异常: ================================================================*/int Lockfile(char * process_name)  {      int fd;      fd = open(FILE_NAME,O_CREAT|O_RDWR,0666);      if( fd == -1)          return -1;          struct flock    stLock;        stLock.l_type = F_WRLCK;        /* F_RDLCK, F_WRLCK, F_UNLCK */      stLock.l_start = 0;    /* byte offset, relative to l_whence */      stLock.l_whence = SEEK_SET;    /* SEEK_SET, SEEK_CUR, SEEK_END */      stLock.l_len = 0;        /* #bytes (0 means to EOF) */         int ret = (fcntl(fd, F_SETLK, &stLock));    if(ret == 0)      {          printf("first run!\n");          sleep(10);        return 0;      }else    {          printf("already run!\n");         return -1;     }   }  int main(int argc , char *agvv[])  {       //if(!is_single_f(FILE_NAME))     if(!Lockfile(FILE_NAME))     printf("\nsingle ok !\n");     else     printf("\ndoule and quit !\n");      return 0;  }  

测试结果:

进程1:

[root@localhost 20151008]# ./flockfirst run!single ok !

进程2:

[root@localhost 20151008]# ./flockalready run!doule and quit !


 

               

                  

0 0
原创粉丝点击