fcntl()、lockf、flockの違い
——lvyilong316
これら3つの関数の機能はファイルをロックすることです。それらの違いは?まず、flock と fcntl はシステムコールで、lockf はライブラリ関数です。 lockf は実際には fcntl のパッケージであるため、lockf と fcntl の基本的な実装は同じであり、ファイルをロックする効果も同じです。後で違いを分析する場合、fcntl と lockf は一緒にされることがほとんどです。まずは各機能の使い方を見て、それぞれの機能の使い方や効果の違いを見ていきましょう。
l関数プロトタイプ
#include
intflock(intfd,intoperation);//fdで指定されたオープンファイルにアドバイザリーロックを適用または削除します
ここで、fdはシステムによって返されるファイルの説明ですcall open シンボル、操作オプションは次のとおりです:
LOCK_SH: 共有ロック
LOCK_EX: 排他ロックまたは排他ロック
LOCK_UN: ロック解除。
LOCK_NB: 非ブロッキング (上記の 3 つの操作で使用されます)
flock 関数について、まず最初に、flock 関数はファイル全体をロックすることしかできず、ファイルの特定の部分をロックすることはできないことを知っておく必要があります。 fcntl/lockf に基づいています。最初の重要な違いは、後者はファイルの特定の領域をロックできることです。第二に、flock は勧告ロックのみを生成できます。 Linux には必須ロック (mandatorylock) と勧告ロック (advisorylock) があることがわかっています。いわゆる強制ロックは、ドアのロックです。最も恐ろしいのは、キーが 1 つしかなく、それを操作できるプロセスが 1 つだけであることです。いわゆるアドバイザリー ロックは、本質的にはファイルにアクセスする前に、まずロックをチェックする必要がある場合に、状況に関係なく読み取りと書き込みを行う必要があります。勧告ロックは効果がありません。プロトコルに準拠し、読み取りまたは書き込みの前にロックをチェックするプロセスは、連携プロセスと呼ばれます。繰り返しますが、flock と fcntl/lockf の違いは主に fork と dup にあります。
(1) flock によって作成されたロックは、fd ではなく、ファイル オープン テーブル エントリ (structfile) に関連付けられます。これは、(fork または dup を介して) ファイル fd をコピーした後、両方の fd を介してロックを操作できる (たとえば、1 つの fd を介してロックし、別の fd を介してロックを解放する) ことができることを意味します。つまり、子プロセスは、親プロセスのロック。ただし、ロック処理中にいずれかの fd がクローズされた場合、ファイル構造が解放されないため、コピーされたすべての fd がクローズされるまでロックは解除されません。プログラムをプログラム 1 にテストします。
l プログラム 1
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <stdio.h><br /></li><li>#include <unistd.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main (int argc, char ** argv)<br /></li><li>{<br /></li><li>int ret;<br /></li><li>int fd1 = open("./tmp.txt",O_RDWR);<br /></li><li>int fd2 = dup(fd1);<br /></li><li>printf("fd1: %d, fd2: %d\n", fd1, fd2);<br /></li><li>ret = flock(fd1,LOCK_EX);<br /></li><li>printf("get lock1, ret: %d\n", ret);<br /></li><li>ret = flock(fd2,LOCK_EX);<br /></li><li>printf("get lock2, ret: %d\n", ret);<br /></li><li>return 0;<br /></li><li>}</li></ol>
実行結果は図に示すように、fd1 のロックは fd2 によるプログラムのロックには影響しません。親子プロセスについては手順2を参照してください。
l プログラム 2
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <stdio.h><br /></li><li>#include <unistd.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main (int argc, char ** argv)<br /></li><li>{<br /></li><li>int ret;<br /></li><li>int pid;<br /></li><li>int fd = open("./tmp.txt",O_RDWR);<br /></li><li>if ((pid = fork()) == 0){<br /></li><li>ret = flock(fd,LOCK_EX);<br /></li><li>printf("chile get lock, fd: %d, ret: %d\n",fd, ret);<br /></li><li>sleep(10);<br /></li><li>printf("chile exit\n");<br /></li><li>exit(0);<br /></li><li>}<br /></li><li>ret = flock(fd,LOCK_EX);<br /></li><li>printf("parent get lock, fd: %d, ret: %d\n", fd, ret);<br /></li><li>printf("parent exit\n");<br /></li><li>return 0;<br /></li><li>}</li></ol>
実行結果は図に示すとおりです。子プロセスはロックを保持しますが、同じ fd を介してロックを取得する親プロセスには影響しません。 。
(2) 同じファイルを 2 回開くには open を使用します。取得された 2 つの fd は独立しています (最下層は 2 つのファイル オブジェクトに対応するため)。一方のファイルではロックされており、もう一方のファイル オブジェクトの前ではロックを解除できません。前のはロックが解除されていますが、ロックもできません。テストプログラムは次のとおりです。
l プログラム 3
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li style="text-align:left;">#include <stdio.h><br /></li><li style="text-align:left;">#include <unistd.h><br /></li><li style="text-align:left;">#include <stdlib.h><br /></li><li style="text-align:left;">#include <sys/file.h><br /></li><li style="text-align:left;">int main (int argc, char ** argv)<br /></li><li style="text-align:left;">{<br /></li><li style="text-align:left;">int ret;<br /></li><li style="text-align:left;">int fd1 = open("./tmp.txt",O_RDWR);<br /></li><li style="text-align:left;">int fd2 = open("./tmp.txt",O_RDWR);<br /></li><li style="text-align:left;">printf("fd1: %d, fd2: %d\n", fd1, fd2);<br /></li><li style="text-align:left;">ret = flock(fd1,LOCK_EX);<br /></li><li style="text-align:left;">printf("get lock1, ret: %d\n", ret);<br /></li><li style="text-align:left;">ret = flock(fd2,LOCK_EX);<br /></li><li style="text-align:left;">printf("get lock2, ret: %d\n", ret);<br /></li><li style="text-align:left;">return 0;<br /></li><li style="text-align:left;">}</li></ol>
結果は図に示すように、fd1 でロックを取得した後、fd2 でロックを取得できなくなります。
(3) exec使用後もファイルロックの状態は変わりません。
(4) NFS ファイルシステムでは flock を使用できません。NFS でファイルロックを使用したい場合は、fcntl を使用してください。
(5) flock ロックは再帰的です。つまり、dup または fork を通じて生成された 2 つの fds をデッドロックなしでロックできます。
l 関数のプロトタイプ
#include
intlockf(intfd,intcmd,off_tlen);
fd は、open によって返されるオープン ファイル記述子です。
cmd の値は次のとおりです。
F_LOCK: ファイルを相互にロックします。ファイルがロックされている場合、ロックが解除されるまでブロックされます。
F_TLOCK: F_LOCK と同じですが、ファイルがロックされている場合はブロックされず、エラーが返されます。
F_ULOCK: ロックが解除されました。
F_TEST: ファイルがロックされているかどうかをテストします。ロックされていない場合は 0 を返し、そうでない場合は -1 を返します。
len: ファイルの現在位置の先頭からロックされる長さ。
関数パラメータの機能を通じて、lockf は排他ロックのみをサポートし、共有ロックをサポートしないことがわかります。
#include
#include
intfcntl(intfd,intcmd,.../*arg*/);
structflock{
...
shortl_type;/*Typeoflock:F_RDLCK,F_WRLCK,F_UNLCK*/
shortl_whence;/*Howtointerpretl_start:SEEK_SET,SEEK_CUR,SEEK_END*/
off_tl_start;/*Startingoffsetforlock*/
off_tl_len;/*Numberofbytestolock*/
pid_tl_pid;/*PIDofprocessblockingourlock(F_GETLKonly)*/
...
};
文件记录加锁相关的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不同。如:
fd1=open(pathname,…);
lockf(fd1,F_LOCK,0);
fd2=dup(fd1);
close(fd2);
则在close(fd2)后,再fd1上设置的锁会被释放,如果将dup换为open,以打开另一描述符上的同一文件,则效果也一样。
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打开该机制。
那么flock和lockf/fcntl所上的锁有什么关系呢?答案时互不影响。测试程序如下:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <unistd.h><br /></li><li>#include <stdio.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main(int argc, char **argv)<br /></li><li>{<br /></li><li>int fd, ret;<br /></li><li>int pid;<br /></li><li>fd = open("./tmp.txt", O_RDWR);<br /></li><li>ret = flock(fd, LOCK_EX);<br /></li><li>printf("flock return ret : %d\n", ret);<br /></li><li>ret = lockf(fd, F_LOCK, 0);<br /></li><li>printf("lockf return ret: %d\n", ret);<br /></li><li>sleep(100);<br /></li><li>return 0;<br /></li><li>}</li></ol>
测试结果如下:
$./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 です。もちろん、このタイプのロックの場合、プロセスが終了した状況が発生します。
5) 08:02:852674 は、対応するディスク ファイルが配置されているデバイスのプライマリ デバイス、マイナー デバイス番号、およびファイルに対応する inodenumber を表します。
6) 0は実際の位置を表します。
7) EOFは終了位置を表します。これら 2 つのフィールドは fcntl タイプの場合により便利で、flock の場合は常に 0 と EOF です。
http://www.bkjia.com/PHPjc/1112546.html