自己紹介

太田一樹。
東京の大学の情報科学科に通う大学生。moratorium満喫中。

お勧め書籍 [全部見る]

飾り

Search


Category Archives

Recent Entries

  1. 論文
  2. JJUG CCCでプレゼンします
  3. kzk's bookshelf
  4. En Google by Gulfweed
  5. PNUTS
  6. コメントスパム対策
  7. Hadoop + Luceneで分散インデクシング
  8. Hadoopの解析資料
  9. Cluster 2008
  10. SWoPP 2008

2007年05月26日

flock(2)はスレッドも排他するか?

以前人づてに、flock(2)がプロセス間排他はするけどスレッド間排他はしないという話を聞いた。

これが本当だと、今まで自分が書いたマルチスレッドアプリケーションのファイルを扱う部分の根幹が揺らいでしまう。特にファイルが壊れたりするような現象は見られなかったので今まで放置してきたが、非常に心配になってきたので調べてみた。

実験環境と検証用コードは以下の通り。

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.
#include <sys/file.h>
#include <pthread.h>
#include <stdio.h>
#include <assert.h>

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;
}

スレッドは200個で、それぞれのスレッドはファイルに追記を行う。ただし毎回flock(2)で保護している。

flock(LOCK_EX)の直後とflock(LOCK_UN)の直前でlockedという変数を変更している。もしflok(2)がスレッドを排他するのであれば、lockedを1にする直前でlockedは必ず0になっているはずである。

さらに、locked = 0にした後でsched_yield(2)を呼び出す事で、明示的に他のスレッドにCPUを明け渡すようにした。こうすることで競合がおきやすくなるはずだ。

これを実行してみた。

dylan% gcc -Wall flock.c -lpthread; rm test.txt; ./a.out

CPUが2つ有るマシンで暫くの間動かしてみたが、assertで落ちる事は無かった。この実験の結果としては、スレッド間で排他できているように思える。

一応、カーネルのコードもささっと読んでみた。file lockの所持者はstruct file_lockのfl_ownerで管理されており、これはfl_owner_tという型で、これはinclude/linux/fs.hで次のように定義されている。

/*
 * 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;

コメントから見る限りスレッドグループについてきちんと考えられてそう。もう一つきになるstruct file_lockのfl_pidについても、current->tgidが代入されているので大丈夫そう。

ただ、「プログラムが間違ってるよ」「カーネル読み間違ってるよ」「たまたま落ちなかっただけでもっと激しくテストしたら落ちるよ」「昔のカーネルだとそうじゃないよ」とか有り得るかもしれないので注意。


trackbacks

trackbackURL:

flock(2) は thread 間で排他するか from 丼日記

「〜ったら?」と言うだけなのもアレなので、書いてみた。ちなみに向こうの comment 欄では deadlock がどうとか世迷い言を言ってるけど、気に...

『flock(2)はスレッドも排他するか?』の関連記事

comments

排他できてるかどうか確認するだけなら、排他できてれば deadlock するような code の方がいいんでは。

  • jun0
  • 2007年05月27日 02:48

しかし排他出来ていないのであれば、このコードで一瞬で止まるはずなのでこれでいいかなーと。証明は得意なjun0さんに任せたっ

  • kzk
  • 2007年05月27日 19:48
comment form
comment form