fcntl関数の使用詳細

5998 ワード

(1)fcntl関数説明
前の5つの基本関数は、ファイルのオープン、読み書きなどの基本的な操作を実現しています。このセクションでは、ファイルが共有されている場合にどのように操作するか、つまり複数のユーザが同じファイルを使って操作する場合、Linuxは通常、ファイルにロックをかけ、共有するリソースが競合する状態にならないようにしています。
ファイルのロックには推奨ロックと強制ロックが含まれています。
提案的なロックは、各ロックファイルのプロセスに対して、ロックがあるかどうかを確認し、既存のロックを尊重することを要求します。一般的にはカーネルとシステムは推奨ロックを使用しない。強制的なロックはカーネルによって実行されます。一つのファイルがロックされて書き込み操作されると、カーネルは他のファイルによる読み書きを停止します。強制ロックを採用することは性能に大きな影響を与え、読み書き操作のたびにロックがあるかどうかを確認しなければならない。
Linuxでは、ファイルのロックを実現する関数はlockとfcntlであり、ここでflockは、ファイルに対して提案的なロックをかけるために用いられ、fcntlは提案的なロックだけでなく、強制的なロックをかけることができる。また、fcntlはファイルのあるレコードをロックすることもできます。つまり記録錠です。
記録ロックはまた、読み取りロックと書き込みロックに分けられ、読み取りロックは共有ロックと呼ばれ、複数のプロセスがファイルの同じ部分に読み取りロックを確立することができる。書き込みロックはまた斥力錠と呼ばれ、いつでもファイルの一部に書き込みロックが作られます。もちろん、ファイルの同じ部分にリードロックと書き込みロックを同時に確立することはできません。
注意:
fcntlは非常に一般的な関数であり、ファイルプロセスの各方面の属性を変更することもできます。本節では、主にそれが記録ロックを作る方法を紹介します。他のユーザーに興味がある読者はfcntlマニュアルを参照してください。
(2)fcntl関数形式
記録ロックを確立するためのfcntl関数フォーマットを表6.6に示します。
表6.6 fcntl関数文法的要点に必要なヘッダファイル

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
関数プロトタイプint fcnt 1(int fd,int cmd,struct flock*lock)
fd:ファイル記述子
F_DUPFD:ファイル記述子をコピーする
F_GETFD:fdのclose-on-execフラグを取得し、もしフラグが設定されていないなら、ファイルはexec関数を経た後も開いたままです。
F_SETFD:close-on-execフラグを設定し、パラメータargのFD_CLOEXECビット決定
F_GETFL:open設定のフラグを取得する
関数の入力値
cmd
F_SETFL:オープン設定を変更するフラグ
F_GETFK:ロックによるロックの有無を説明します。
F_SETFK:ロック記述のファイルロックを設定する
F_SETLKW:これはF_ですSETLKのブロックバージョン(コマンド名のWは待ちを表します。)
他のロックがある場合は、プロセス睡眠を呼び出します。信号をキャッチすると睡眠が中断されます。
F_GETOWN:SIGIOとSIGURG信号を受信するプロセス番号またはプロセスグループ番号を検索します。
F_SETOWN:プロセス番号またはプロセスグループ番号を設定する
関数の戻り値
ロック:構造はflockで、記録ロックの具体的な状態を設定して、後で詳しく説明します。
成功:0
-1:エラー
ここで、ロックの構造は以下の通りです。

Struct flock{
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}
ロック構造における各変数の値の意味は表6.7に示されている。
表6.7ロック構造変数の取得値
F_RDUCK:リードロック(共有ロック)
l_typeWRLCK:書き込みロック(反発ロック)
F_UNLCK:ロック解除
l_stat相対変位量(バイト)
SEEK_SET:現在位置はファイルの先頭で、新しい位置はオフセット量の大きさです。
SEEK_CUR:現在位置はファイルポインタの位置で、新しい位置は現在位置にオフセットを加えます。
l_whence:相対変位量の起点(同lseekのwhence)。
SEEK_END:現在位置はファイルの末尾で、新しい位置はファイルのサイズにオフセットの大きさを加えます。
l_lenロックエリアの長さ
テクニック:
ファイル全体をロックするためには、通常はl_をロックする方法があります。startは0と説明しています。l_whenceはSEEK_と説明しています。SET,l_lenは0と説明する。
(3)fcntl使用例
まず、fcntl関数を用いたファイル記録ロック関数を示します。この関数では、まずflock構造体の対応するビットに対応する値を与える。次に、関連ファイルに施錠できるかどうかと判断するために、fcntl関数を2回使用します。ここで使用するcmdの値はそれぞれF_です。SETLKとF_GETLK
この関数のソースコードは以下のように示されています。

/*lock_set */
void lock_set(int fd, int type)
{
struct flock lock;
lock.l_whence = SEEK_SET;// lock
lock.l_start = 0;
lock.l_len =0;
while(1){
lock.l_type = type;
/* type */
if((fcntl(fd, F_SETLK, &lock)) == 0){
if( lock.l_type == F_RDLCK )
printf("read lock set by %d
",getpid());
else if( lock.l_type == F_WRLCK )
printf("write lock set by %d
",getpid());
else if( lock.l_type == F_UNLCK )
printf("release lock by %d
",getpid());
return;
}
/* */
fcntl(fd, F_GETLK,&lock);
/* */
if(lock.l_type != F_UNLCK){
/*/ */
if( lock.l_type == F_RDLCK )
printf("read lock already set by %d
",lock.l_pid);
/* */
else if( lock.l_type == F_WRLCK )
printf("write lock already set by %d
",lock.l_pid);
getchar();
}
}
}
の下の例はテストファイルの書き込みロックです。ここでまずハローファイルを作成し、その後にロックを書き込み、最後に書き込みロックを解除します。コードは以下の通りです。

/*fcntl_write.c */
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
/* */
fd=open("hello",O_RDWR | O_CREAT, 0666);
if(fd < 0){
perror("open");
exit(1);
}
/* */
lock_set(fd, F_WRLCK);
getchar();
/* */
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}
は複数の端末を使用するために、書き込みロックの役割をより良く表示するために、本例は主にPCマシンでテストし、読者はそれらをクロスコンパイルして、ターゲットボードにダウンロードして実行します。以下はPCマシンでの運転結果です。プログラムの柔軟性を大きくするために、私はファイルを使ってロックした後、ユーザーが任意のキーを押してプログラムを実行させます。読者は二つの端末を開いて、二つの端末で同時にこのプログラムを実行して、複数のプロセスが一つのファイルを操作する効果を達成することを提案します。ここでは、まず端末1を実行します。端末2の中の最初の文に注意してください。端末1:

[root@localhost file]# ./fcntl_write
write lock set by 4994
release lock by 4994
端末2:

[root@localhost file]# ./fcntl_write
write lock already set by 4994
write lock set by 4997
release lock by 4997
より分かるように、書き込みロックは相互反発ロックであり、書き込みロックは1つの時間に1つしか存在しない。次のプログラムはテストファイルの読み取りロックです。原理は上のプログラムと同じです。

/*fcntl_read.c */
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
fd=open("hello",O_RDWR | O_CREAT, 0666);
if(fd < 0){
perror("open");
exit(1);
}
/* */
lock_set(fd, F_RDLCK);
getchar();
/* */
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}
も同様に2つの端末を開いて、まず端末1のプログラムを起動させ、その実行結果は以下の通りである。端末1:

[root@localhost file]# ./fcntl2
read lock set by 5009
release lock by 5009
端末2:

[root@localhost file]# ./fcntl2
read lock set by 5010
release lock by 5010
読者はこの結果を書き込みロックの運転結果と比較してもよく、読み取りロックは共有ロックであり、プロセス5009がリードロックを設定した後に、プロセス5010はリードロックを設定することもできる。思考:一方の端末に読取ロックを設置すると、もう一つの端末に書き込みロックを作動させると、どのような結果がありますか?