- 2007-05-26 (Sat) 6:02
- Unix

以前人づてに、flock(2)がプロセス間排他はするけどスレッド間排他はしないという話を聞いた。
これが本当だと、今まで自分が書いたマルチスレッドアプリケーションのファイルを扱う部分の根幹が揺らいでしまう。特にファイルが壊れたりするような現象は見られなかったので今まで放置してきたが、非常に心配になってきたので調べてみた。
実験環境と検証用コードは以下の通り。
[code]
dylan% uname -a
Linux dylan 2.6.17-10-generic #2 SMP Tue Dec 5 22:28:26 UTC 2006 i686 GNU/Linux
dylan% gcc –version
gcc (GCC) 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[/code]
[code]
#include
#include
#include
static int locked = 0;
static pthread_mutex_t locked_mutex = PTHREAD_MUTEX_INITIALIZER;
void*
func1(void* arg)
{
int r;
char ch = (char)arg;
while (1) {
FILE *f = fopen(”test.txt”, “a+”);
assert(f != NULL);
int fd = fileno(f);
assert(f >= 0);
r = flock(fd, LOCK_EX);
assert(r == 0);
pthread_mutex_lock(&locked_mutex);
assert(locked == 0);
locked = 1;
pthread_mutex_unlock(&locked_mutex);
fwrite(&ch, 1, 1, f);
fwrite(&ch, 1, 1, f);
printf(”%d\n”, pthread_self());
pthread_mutex_lock(&locked_mutex);
locked = 0;
pthread_mutex_unlock(&locked_mutex);
sched_yield();
r = flock(fd, LOCK_UN);
assert(r == 0);
fflush(f);
fclose(f);
}
return NULL;
}
#define THREAD_NUM 200
int
main(void)
{
pthread_t ths[THREAD_NUM];
int i;
for (i = 0; i < THREAD_NUM; i++) {
char ch = 'a' + i;
pthread_create(&ths[i], NULL, func1, (void*)ch);
}
for (i = 0; i < THREAD_NUM; i++)
pthread_join(ths[i], NULL);
return 0;
}
[/code]
スレッドは200個で、それぞれのスレッドはファイルに追記を行う。ただし毎回flock(2)で保護している。
flock(LOCK_EX)の直後とflock(LOCK_UN)の直前でlockedという変数を変更している。もしflok(2)がスレッドを排他するのであれば、lockedを1にする直前でlockedは必ず0になっているはずである。
さらに、locked = 0にした後でsched_yield(2)を呼び出す事で、明示的に他のスレッドにCPUを明け渡すようにした。こうすることで競合がおきやすくなるはずだ。
これを実行してみた。
[code]
dylan% gcc -Wall flock.c -lpthread; rm test.txt; ./a.out
[/code]
CPUが2つ有るマシンで暫くの間動かしてみたが、assertで落ちる事は無かった。この実験の結果としては、スレッド間で排他できているように思える。
一応、カーネルのコードもささっと読んでみた。file lockの所持者はstruct file_lockのfl_ownerで管理されており、これはfl_owner_tという型で、これはinclude/linux/fs.hで次のように定義されている。
[code]
/*
* The POSIX file lock owner is determined by
* the "struct files_struct" in the thread group
* (or NULL for no owner - BSD locks).
*
* Lockd stuffs a "host" pointer into this.
*/
typedef struct files_struct *fl_owner_t;
[/code]
コメントから見る限りスレッドグループについてきちんと考えられてそう。もう一つきになるstruct file_lockのfl_pidについても、current->tgidが代入されているので大丈夫そう。
ただ、「プログラムが間違ってるよ」「カーネル読み間違ってるよ」「たまたま落ちなかっただけでもっと激しくテストしたら落ちるよ」「昔のカーネルだとそうじゃないよ」とか有り得るかもしれないので注意。
Similar Posts:
- Newer: 係り受け解析: 論文読み
- Older: 演習3二期開始
Comments:3
- jun0 07-05-27 (Sun) 2:48
-
排他できてるかどうか確認するだけなら、排他できてれば deadlock するような code の方がいいんでは。
- 丼日記 07-05-27 (Sun) 9:52
-
flock(2) は thread 間で排他するか
「〜ったら?」と言うだけなのもアレなので、書いてみた。ちなみに向こうの comment 欄では deadlock がどうとか世迷い言を言ってるけど、気に…
- kzk 07-05-27 (Sun) 19:48
-
しかし排他出来ていないのであれば、このコードで一瞬で止まるはずなのでこれでいいかなーと。証明は得意なjun0さんに任せたっ
Trackbacks:0
- Trackback URL for this entry
- http://kzk9.net/blog/2007/05/flock2.html/trackback
- Listed below are links to weblogs that reference
- flock(2)はスレッドも排他するか? from moratorium
