C言語でflockという関数を使った、ロックファイルによる排他処理をする方法です!
意外と簡単に排他できちゃうので、なかなか良さげです!
環境
項目 | 内容 |
---|---|
OS | Ubuntu 16.4 |
コンパイラ | gcc |
事前準備
はじめにロックファイルを作っておかないといけません。
今回は「/home/<user-name>/work/test/」に、「.lock」というファイルを作って使うことします。
$ cd ~/work/test $ touch .lock
作ったもの
こんなものを作ってみました。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/file.h> #define LOCK_FILE "/home/<user-name>/work/test/.lock" // ロックファイルのfdを取得 int openLockFile(char* path) { const int fd = open(path, O_WRONLY | O_APPEND); if (fd < 0) { perror("ERROR] cant open lock file "); exit(EXIT_FAILURE); } return fd; } // ロック void mmLock(int lock) { if ( flock(lock, LOCK_EX) != 0 ){ perror("ERROR] faild flock "); exit(EXIT_FAILURE); } } // アンロック void mmUnlock(int lock){ flock(lock, LOCK_UN); close(lock); } // スレッド処理 void proc() { if (fork() == 0) { const int lockFd = openLockFile(LOCK_FILE); mmLock(lockFd); printf("\nfile locking...\n"); // 何かしらの処理 ------------------------- printf("何かしらの処理(10秒待機)\n"); sleep(10); //----------------------------------------- mmUnlock(lockFd); printf("file unlock!!!!\n"); } } // メイン int main() { printf("--start--\n"); proc(); printf("--end--\n"); return 0; }
実行すると?
コンパイルをしたら、ターミナルを2つ実行しておきます(T1,T2とする)。
T1で実行してロックがされた後に、T2で実行してみましょう。
T2はすぐには処理(出力)がされず、T1がアンロックしたタイミングで動き出します。
ロックに関する関数の解説
各処理について見ていきます。
fdを取得する
fdを取得するには、ファイルオープンする必要があります。
const int fd = open(path, O_WRONLY | O_APPEND);
今回の場合、
- 書き込み専用モード
- 追記モード
で開いています。
ロック
ファイルのロックは、flock()を使用します。
flock(fd, LOCK_EX);
引数は
引数 | 内容 |
---|---|
第1引数 | 取得したfd |
第2引数 | LOCK_EX(排他ロック) |
LOCK_EXは、「排他ロックしてね!」を指示します。
LOCK_EX
排他ロックを適用する。 指定したファイルに対して、 ただ一つのプロセスだけが同時に排他ロックを保持することができる。
引用: Man page of FLOCK
成功した場合、0が返ってきます。
アンロック
ファイルのアンロックも、flock()を使用します。
flock(lock, LOCK_UN);
引数は
引数 | 内容 |
---|---|
第1引数 | 取得したfd |
第2引数 | LOCK_UN(ロック解除) |
LOCK_UN
このプロセスが保持している既存のロックを解除する。
引用: Man page of FLOCK
成功した場合、0が返ってきます。
参考
コチラを参考にしました。ありがとうございました。
あとがき
C言語でロックファイルで排他処理をする方法でした!
簡単な方法で排他処理ができちゃうんですね。
割と驚きました。
知ってしまえば便利そうなので、是非試してみてください!