IPC: ファイル・ロック
ファイルのロックを行い安全にファイルを操作する。
SYNOPSIS
#include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fildes, int cmd, /* arg */ ...);
DESCRIPTION
安全にファイルをコントロールするために、操作したいファイルをロックして他のプロセスから一時的に利用できなくします。System V 系の UNIX では lockf()
関数、BSD系では flock()
関数がそれぞれ用意されていますが、ファイルをコントロールするには移植性や確実性で一番よいと思う fcntl()
システムコールを使用して説明します。
fcntl()
システムコールを使用してファイルをロックする場合、どのようにロックするか flock 構造体を使って設定しなければなりません。
struct flock fl; int fd; fl.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */ fl.l_start = 0; /* Offset from l_whence */ fl.l_len = 0; /* length, 0 = to EOF */ fl.l_pid = getpid(); /* our PID */ fd = open("filename", O_WRONLY); fcntl(fd, F_SETLKW, &fl); /* F_GETLK, F_SETLK, F_SETLKW */
flock 構造体のメンバについて(ファイルのロックに関するフラグのみ解説)
l_type |
ロックの種類を指定します。読み込みに対してのロックは ロックの種類に対応する
|
||||||
l_whence |
ロックを開始するオフセットを指定します。ファイルの始めなら SEEK_SET 、現在位置からは SEEK_CUR 、ファイルの終わりからなら SEEK_END を指定します。 |
||||||
l_start |
l_whence で指定したところから何バイト目をオフセットにするか指定します。 |
||||||
l_len |
l_startで指定したオフセットから何バイトまでロックの対象にするか指定します。0 は EOF (End of File) までです。 |
||||||
l_pid |
ロックを有効にできるプロセス ID を指定します。通常、自分自身なので getpid()関数を使用して自分のプロセス ID をセットします。 |
fcntl()
システムコールへのコマンドについて(2番目の引数:ファイルのロックに関するコマンドのみ解説)
F_SETLKW |
flock構造体で指定された内容でファイルをロックします。もしロックを試みたファイルがすでにロックされていた場合は、ロックが可能になるまで待ちます。 |
F_SETLK |
F_SETLKW とほとんど同じですが、指定のファイルがすでにファイルがロックされている場合ロックが出来なかったことを示す -1 を返します。このコマンドは、ファイルのロックを解除するF_UNLCK を行う際にも使用されます。 |
F_GETLK |
ファイルがロックされているかチェックする際に使用します。 |
ロックの解除は、プログラム中のロックを解除したいところで以下のように指定します。
fl.l_type = F_UNLCK; /* tell it to unlock the region */ fcntl(fd, F_SETLK, &fl); /* set the region to unlocked */
SAMPLE
パイプに対して書き込んだ内容を読み込みます。
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int main() { struct flock fl; int fd; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); if ((fd = open("lock.txt", O_RDWR)) == -1) { perror("open"); exit(1); } printf("Press <Enter> to try to get lock: "); getchar(); fputs("waiting...", stdout); if (fcntl(fd, F_SETLKW, &fl) == -1) { perror("fcntl"); exit(1); } puts("Locked."); printf("Press <Enter> to release lock: "); getchar(); fl.l_type = F_UNLCK; if (fcntl(fd, F_SETLK, &fl) == -1) { perror("fcntl"); exit(1); } puts("Unlocked."); close(fd); return 0; }
これをコンパイルし実行すると以下のようになります。
<< SHELL-1 >> # gcc flock_sample.c -o flock_sample # touch lock.txt # ./flock_sample Press <Enter> to try to get lock: <Enter> waiting...Locked. Press <Enter> to release lock:
上記の状態で、ファイルがロックされています。別のシェルでもう一度プログラムを起動してみます。
<< SHELL-2 >> # ./flock_sample Press <Enter> to try to get lock: <Enter> waiting...
SHELL-1 でファイルをロックしているため、SHELL-2 ではロックが解除されるまで待っています。ここで、SHELL-1 で Enter
キーをタイプしてロックを解除すると、SHELL-2 でファイルをロックします。
SEE ALSO
fcntl(2), open(2)