您的位置 首页 技术

你知道在Linux中fcntl()、lockf、flock的差异?

你知道在Linux中fcntl()、lockf、flock的区别?-关于flock函数,首先要知道flock函数只能对整个文件上锁,而不能对文件的某一部分上锁,这是于fcntl/lockf的第一个重要区别,后者可以对文件的某个区域上锁。

这三个函数的作用都是给文件加,那它们有什么差异呢?首要flock和fcntl是体系调用,而lockf是库函数。lockf实际上是fcntl的封装,所以lockf和fcntl的底层实现是相同的,对文件加锁的作用也是相同的。后边剖析不同点时大多数情况是将fcntl和lockf放在一同的。下面首要看每个函数的运用,从运用的方法和作用来看各个函数的差异

1.flock

函数原型

intflock(intfd,intoperation);//Applyorremoveanadvisorylockontheopenfilespecifiedbyfd,仅仅建议性锁

其间fd是体系调用open回来的文件描述符,operaTIon的选项有:

LOCK_SH:同享锁

LOCK_EX:排他锁或许独占锁

LOCK_UN:解锁。

LOCK_NB:非堵塞(与以上三种操作一同运用)

关于flock函数,首要要知道flock函数只能对整个文件上锁,而不能对文件的某一部分上锁,这是于fcntl/lockf的第一个重要差异,后者能够对文件的某个区域上锁。其次,flock只能发生劝说性锁。咱们知道,linux存在强制锁(mandatorylock)和劝说锁(advisorylock)。所谓强制锁,比较好了解,便是你家大门上的那把锁,最要命的是只要一把钥匙,只要一个进程能够操作。所谓劝说锁,实质是一种协议,你拜访文件前,先检查锁,这时候锁才其作用,假如你不那么kind,不管三七二十一,就要读写,那么劝说锁没有任何的作用。而恪守协议,读写前先检查锁的那些进程,叫做协作进程。再次,flock和fcntl/lockf的差异主要在fork和dup。

(1)flock创立的锁是和文件翻开表项(structfile)相关联的,而不是fd。这就意味着仿制文件fd(经过fork或许dup)后,那么经过这两个fd都能够操作这把锁(例如经过一个fd加锁,经过另一个fd能够开释锁),也便是说子进程承继父进程的锁。可是上锁过程中封闭其间一个fd,锁并不会开释(由于file结构并没有开释),只要封闭一切仿制出的fd,锁才会开释。测验程序入程序一。

程序一

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include

#include

#include

#include

int main (int argc, char ** argv)

{

int ret;

int fd1 = open(“./tmp.txt”,O_RDWR);

int fd2 = dup(fd1);

printf(“fd1: %d, fd2: %d\n”, fd1, fd2);

ret = flock(fd1,LOCK_EX);

printf(“get lock1, ret: %d\n”, ret);

ret = flock(fd2,LOCK_EX);

printf(“get lock2, ret: %d\n”, ret);

return 0;

}

运转成果如图,对fd1上锁,并不影响程序经过fd2上锁。关于父子进程,参阅程序二。

程序二

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include

#include

#include

#include

int main (int argc, char ** argv)

{

int ret;

int pid;

int fd = open(“./tmp.txt”,O_RDWR);

if ((pid = fork()) == 0){

ret = flock(fd,LOCK_EX);

printf(“chile get lock, fd: %d, ret: %d\n”,fd, ret);

sleep(10);

printf(“chile exit\n”);

exit(0);

}

ret = flock(fd,LOCK_EX);

printf(“parent get lock, fd: %d, ret: %d\n”, fd, ret);

printf(“parent exit\n”);

return 0;

}

运转成果如图,子进程持有锁,并不影响父进程经过相同的fd获取锁,反之亦然。

(2)运用open两次翻开同一个文件,得到的两个fd是独立的(由于底层对应两个file目标),经过其间一个加锁,经过另一个无法解锁,而且在前一个解锁前也无法上锁。测验程序如程序三:

程序三

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include

#include

#include

#include

int main (int argc, char ** argv)

{

int ret;

int fd1 = open(“./tmp.txt”,O_RDWR);

int fd2 = open(“./tmp.txt”,O_RDWR);

printf(“fd1: %d, fd2: %d\n”, fd1, fd2);

ret = flock(fd1,LOCK_EX);

printf(“get lock1, ret: %d\n”, ret);

ret = flock(fd2,LOCK_EX);

printf(“get lock2, ret: %d\n”, ret);

return 0;

}

成果如图,经过fd1获取锁后,无法再经过fd2获取锁。

(3)运用exec后,文件锁的情况不变。

(4)flock不能再NFS文件体系上运用,假如要在NFS运用文件锁,请运用fcntl。

(5)flock锁可递归,即经过dup或许或许fork发生的两个fd,都能够加锁而不会发生死锁。

2.lockf与fcntl

函数原型

#include

intlockf(intfd,intcmd,off_tlen);

fd为经过open回来的翻开文件描述符。

cmd的取值为:

F_LOCK:给文件互斥加锁,若文件以被加锁,则会一向堵塞到锁被开释。

F_TLOCK:同F_LOCK,但若文件已被加锁,不会堵塞,而回回来过错。

F_ULOCK:解锁。

F_TEST:测验文件是否被上锁,若文件没被上锁则回来0,不然回来-1。

len:为从文件当时方位的开始要锁住的长度。

经过函数参数的功用,能够看出lockf只支撑排他锁,不支撑同享锁。

1

2

3

4

5

6

7

8

9

10

11

12

#include

#include

int fcntl(int fd, int cmd, … /* arg */ );

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 (F_GETLK only) */

…        

};

文件记载加锁相关的cmd分三种:

F_SETLK:请求锁(读锁F_RDLCK,写锁F_WRLCK)或许开释所(F_UNLCK),可是假如kernel无法将锁颁发本进程(被其他进程抢了先,占了锁),不傻等,回来error。

F_SETLKW:和F_SETLK简直相同,仅有的差异,这厮是个死心眼的主儿,请求不到,就傻等。

F_GETLK:这个接口是获取锁的相关信息:这个接口会修正咱们传入的structflock。

经过函数参数功用能够看出fcntl是功用最强壮的,它既支撑同享锁又支撑排他锁,即能够锁住整个文件,又能只锁文件的某一部分。

下面看fcntl/lockf的特性:

(1)上锁可递归,假如一个进程对一个文件区间现已有一把锁,后来进程又妄图在同一区间再加一把锁,则新锁将替换老锁。

(2)加读锁(同享锁)文件有必要是读翻开的,加写锁(排他锁)文件有必要是写翻开。

(3)进程不能运用F_GETLK指令来测验它自己是否再文件的某一部分持有一把锁。F_GETLK指令界说阐明,回来信息指示是否现存的锁阻挠调用进程设置它自己的锁。由于,F_SETLK和F_SETLKW指令总是替换进程的现有锁,所以调用进程绝不会堵塞再自己持有的锁上,所以F_GETLK指令绝不会陈述调用进程自己持有的锁。

(4)进程停止时,他所树立的一切文件锁都会被开释,队医flock也是相同的。

(5)任何时候封闭一个描述符时,则该进程经过这一描述符能够引证的文件上的任何一把锁都被开释(这些锁都是该进程设置的),这一点与flock不同。如:

1

2

3

4

fd1 = open(pathname, …);

lockf(fd1, F_LOCK, 0);

fd2 = dup(fd1);

close(fd2);

则在close(fd2)后,再fd1上设置的锁会被开释,假如将dup换为open,以翻开另一描述符上的同一文件,则作用也相同。

1

2

3

4

fd1 = open(pathname, …);

lockf(fd1, F_LOCK, 0);

fd2 = open(pathname, …);

close(fd2);

(6)由fork发生的子进程不承继父进程所设置的锁,这点与flock也不同。

(7)在履行exec后,新程序能够承继原程序的锁,这点和flock是相同的。(假如对fd设置了close-on-exec,则exec前会封闭fd,相应文件的锁也会被开释)。

(8)支撑强制性锁:对一个特定文件翻开其设置组ID位(S_ISGID),并封闭其组履行位(S_IXGRP),则对该文件敞开了强制性锁机制。再Linux中假如要运用强制性锁,则要在文件体系mount时,运用_omand翻开该机制。

3.两种锁的联系

那么flock和lockf/fcntl所上的锁有什么联系呢?答案时互不影响。测验程序如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include

#include

#include

#include

int main(int argc, char **argv)

{

int fd, ret;

int pid;

fd = open(“./tmp.txt”, O_RDWR);

ret = flock(fd, LOCK_EX);

printf(“flock return ret : %d\n”, ret);

ret = lockf(fd, F_LOCK, 0);

printf(“lockf return ret: %d\n”, ret);

sleep(100);

return 0;

}

测验成果如下:

$./a.out

flockreturnret:0

lockfreturnret:0

可见flock的加锁,并不影响lockf的加锁。两外咱们能够经过/proc/locks检查进程获取锁的情况。

$psaux|grepa.out|grep-vgrep

123751188490.00.011904440pts/5S+01:090:00./a.out

$sudocat/proc/locks|grep18849

1:POSIXADVISORYWRITE1884908:02:8526740EOF

2:FLOCKADVISORYWRITE1884908:02:8526740EOF

咱们能够看到/proc/locks下面有锁的信息:我现在别离叙说下意义:

1)POSIXFLOCK这个比较清晰,便是哪个类型的锁。flock体系调用发生的是FLOCK,fcntl调用F_SETLK,F_SETLKW或许lockf发生的是POSIX类型,有次可见两种调用发生的锁的类型是不同的;

2)ADVISORY标明是劝说锁;

3)WRITE望文生义,是写锁,还有读锁;

4)18849是持有锁的进程ID。当然关于flock这种类型的锁,会呈现进程现已退出的情况。

5)08:02:852674表明的对应磁盘文件的地点设备的主设备好,次设备号,还有文件对应的inodenumber。

6)0表明的是所的其实方位

7)EOF表明的是完毕方位。这两个字段对fcntl类型比较有用,对flock来是总是0和EOF。

 

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/jishu/89621.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部