読者です 読者をやめる 読者になる 読者になる

「C」ファイルのロックを取得してみる

C でファイルのロックを取得するサンプルを書いてみたので、メモしておきます。

ロックは flock(int fd, int operation) 関数で取得できるみたいです。
fd には open 関数で取得したファイルディスクリプタを、operation はロックの種類 (*1) を指定する。

Man page of FLOCK

(*1)
LOCK_SH : 共有ロック
LOCK_EX : 排他ロック
LOCK_UN : ロック解除


以下サンプルです。
※ ちゃんとロックが効いてるかどうかわかりやすくするために、flock 関数実行前後で printf 関数の実行、ロック解除前に getchar 関数で処理を止めるようにしています。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>

void main()
{
    char *path = "file";
    int fd;
    char *output_buf = "hoge uga oro\n";
    char input_buf[100];
    
    fd = open(path, O_WRONLY | O_APPEND);
    if(fd == -1) {
        perror("open");
        exit(1);
    }
    
    printf("lock start\n");
    if((flock(fd, LOCK_EX) != 0)) {
        perror("lock");
        exit(1);
    }
    printf("lock OK\n");
    
    write(fd, output_buf, strlen(output_buf));
    
    getchar();
    
    if((flock(fd, LOCK_UN) != 0)) {
        perror("unlock");
        exit(1);
    }
    
    close(fd);
}

上記を別々のコンソールなんかから ( 別々のプロセスとして ) 実行すると、後から実行した方 ( コンソール2 ) がロック獲得待ちになって、ちゃんと排他ロックが効いてることが確認できる。
■ コンソール1

lock start
lock OK

■ コンソール2

lock start

※ コンソール1側でロック解除されると、コンソール2側でロックが獲得されます。


ただ、UNIX 系 OS は、advisory lock になるので、基本的に他のプロセスにロックに従った動きを強制させることができないみたいです。ちゃんとロック働かせようと思うと、上記みたいにそれぞれのプロセスがロックを意識した実装にしないといけない。

ファイルロック - Wikipedia

例えば、上記の場合、コンソール2で以下みたいにロックを意識してない実装とすると、排他ロックを普通に無視する。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>

void main()
{
    char *path = "file";
    int fd;
    char *output_buf = "ahe ahe ahe\n";
    char input_buf[100];
    
    fd = open(path, O_WRONLY);
    if(fd == -1) {
        perror("open");
        exit(1);
    }
    
    write(fd, output_buf, strlen(output_buf));
    
    close(fd);
}


以上になります。

[環境情報]
Ubuntu 14.04
gcc 4.8.2