linux c 文件锁应用详解汇总

Linux系统中,文件上锁的函数有两个flock和fcntl ,前者主要是加建议性锁,后者既可以加建议性锁(默认)也可以加强制性锁,而且它还可以给某一记录进行上锁,即所谓的记录锁。

fcntl文件锁有两种类型:建议性锁 和强制性锁
  建议性锁是这样规定的:每个使用上锁文件的进程都要检查是否有锁存在,当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁,它们依靠程序员遵守这个规定。
  强制性锁是由内核执行的。当文件被上锁来进行写入操作时,在锁定该文件的进程释放该锁之前,内核会阻止任何对该文件的读或写访问,每次读或写访问都得检查锁是否存在。

系统默认fcntl都是建议性锁,强制性锁是非POSIX标准的。如果要使用强制性锁,要使整个系统可以使用强制性锁,那么得需要重新挂载文件系统,mount使用参数 -0 mand打开强制性锁,或者关闭已加锁文件的组执行权限并且打开该文件的set-GID权限位。

建议性锁只在cooperating processes之间才有用,对cooperating process的理解是最重要的,它指的是会影响其它进程的进程或被别的进程所影响的进程,举两个例子:(1)我们可以同时在两个窗口中运行同一个命令, 对同一个文件进行操作,那么这两个进程就是cooperatingprocesses;(2)cat file| sort,那么cat和sort产生的进程就是使用了pipe的cooperating processes。

使用fcntl文件锁进行I/O操作必须小心:进程在开始任何I/O操作前如何去处理锁,在对文件解锁前如何完成所有的操作,是必须考虑的。如果在设置锁 之前打开文件,或者读取该锁之后关闭文件,另一个进程就可能在上锁/解锁操作和打开/关闭操作之间的几分之一秒内访问该文件。当一个进程对文件加锁后,无论它是否释放所加的锁,只要文件关闭,内核都会自动释放加在文件上的建议性锁(这也是建议性锁和强制性锁的最大区别),所以不要想设置建议性锁来达到永久不让别的进程访问文件的目的(强制性锁才可以);强制性锁则对所有进程起作用。

fcntl常用的有三个参数F_SETLK /F_SETLKW,F_UNLCK和F_GETLK,来分别要求、释放、测试record locks,record locks是对文件一部分而不是整个文件的锁,这种细致的控制使得进程更好地协作以共享文件资源。fcntl能够用于读取锁和写入锁,read lock也叫shared lock(共享锁),因为多个cooperating process能够在文件的同一部分建立读取锁;writelock被称为exclusive lock(排斥锁),因为任何时刻只能有一个cooperating process在文件的某部分上建立写入锁。如果cooperatingprocesses对文件进行操作,那么它们可以同时对文件加read lock,在一个cooperating process加write lock之前,必须释放别的cooperating process加在该文件的read lock和wrtie lock,也就是说,对于文件只能有一个write lock存在,read lock和wrtie lock不能共存。

 

一、 flock用法详解

在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock。

flock, 建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。

表头文件 #include<sys/file.h>

定义函数  int flock(int fd,intoperation);

函数说明  flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。为了更好的移植性,对于文件的打开与关闭可以选择fopen和fclose的组合,但flock的第一个参数要求的是int类型的文件描述符。这里对fopen返回的FILE类型的文件指针进行转换,转换为int型的文件描述符 (假设open函数返回的文件描述符为fd,而fopen返回的文件指针为*fp,则fd等价于fp->_fileno或fileno(fd)).

  参数  operation有下列四种情况:

  LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。

  LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。

  LOCK_UN 解除文件锁定状态。

  LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。

  单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。

  返回值  返回0表示成功,若有错误则返回-1,错误代码存于errno。

说明:

进程使用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会随着进程的关闭而被自动释放掉。

flock只要在打开文件后,需要对文件读写之前flock一下就可以了,用完之后再flock一下,前面加锁,后面解锁。示例问题描述如下:

一个进程去打开文件,输入一个整数,然后上一把写锁(LOCK_EX),再输入一个整数将解锁(LOCK_UN),另一个进程打开同样一个文件,直接向文件中写数据,发现锁不起作用,能正常写入(我此时用的是超级用户)。google了一大圈发现flock不提供锁检查,也就是说在用flock之前 需要用户自己去检查一下是否已经上了锁,说明白点就是读写文件之前用一下flock检查一下文件有没有上锁,如果上锁了flock将会阻塞在那里(An attempt to lock the fileusing one of these file descriptors may be denied by a lock that the callingprocess has already placed via another descriptor ),除非用了LOCK_NB。

    注意:关闭文件后,锁将失效!

例一:非阻塞

//lockfile.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
    int fd,i;
    char path[]="/home/taoyong/test.txt";
    extern int errno;
    fd=open(path,O_WRONLY|O_CREAT);
    if(fd!=-1)
        {
        printf("open file %s ./n",path);
        printf("please input a numberto lock the file./n");
        scanf("%d",&i);
        if(flock(fd,LOCK_EX)==0)
            {
           printf("

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值