プロフィール

kosaki

Author:kosaki
連絡先はコチラ

ブログ検索
最近の記事
最近のコメント
最近のトラックバック
リンク
カテゴリー
月別アーカイブ
RSSフィード
FC2ブログランキング

スポンサーサイト このエントリーをはてなブックマークに追加

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


スポンサー広告 | 【--------(--) --:--:--】 | Trackback(-) | Comments(-)

なんで、pthread_once()なんて存在するの? このエントリーをはてなブックマークに追加

http://d.hatena.ne.jp/amachang/20080612/1213244820


お気に入りなサイトのIT戦記より


// ここを volatile にする
// (この変数の値はアトミック(つまり、レジスタにだけあってメモリにないということがない変数に)になる)
volatile char* p = NULL;
pthread_mutex_t m;

void* f(void* _p) {

// ロックかからない
if (p == NULL) {
pthread_mutex_lock(&m);

// ここからはクリティカルセクション

// 一個目の初期化時にここでブロックしたスレッドのために
// もう一回 NULL チェック
if (p == NULL) {

// ここではまだ p に代入しない
// 代入したら別スレッドで初期化されていない p が返ってしまう
char* tmp = (char*)malloc(10);
strcpy(tmp, "hoge");

// クリティカルセクションの最後で代入
p = tmp;
}
pthread_mutex_unlock(&m);
}

*(char**)_p = p;
}


バグっとるよ。
コンパイラは最適化で、tmpを消してpに直接malloc結果を入れる権利があるので、
最初のロック外のif文で!NULLになっても、それは初期化が終わってないかもしれない。

基本的にメモリバリアーを理解してないと、DCLパターンは地雷。
pthread_once()推奨。
(てゆーか、まさにこのためにpthread_once()はある。pthread_mutex()から構築できるようなコンビニエンス関数は規格に入れないぜ。といっていたPOSIXがpthread_onceを入れた理由はここにある)

以下、わかりやすいまとめサイトへの誘導。

バイナリアンなmemologueさんのサイト:
http://d.hatena.ne.jp/yupo5656/20041011/p1


注意: このページではx86用のメモリバリアを
   __asm__ __volatile__ ( "" ::: "memory" );
と紹介していますが、これはユニプロセッサ用なので、Core DuoなまかーなAmachanはちゃんとlfence, sfence命令を入れないとやばいです。


Effective C++を書いたScott Meyersさんのサイト
http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf


最近、社内向けにメモリバリアのドキュメントを書いたばかりなので、反響があればブログにうpする。


バリアー
光子力バリアー! ランキング!


関連記事


linux | 【2008-06-16(Mon) 11:59:22】 | Trackback:(0) | Comments:(5)
コメント

> ちゃんとlfence, sfence命令を入れないとやばいです。
これ、本当なんでしょうか?
Intel 64 and IA-32 Architectures Software Developer's Manual
Volume 3A: System Programming Guide, Part 1
http://www.intel.com/products/processor/manuals/index.htm
の 7.2 MEMORY ORDERING の記述に拠れば、
Core 2 Duoなどの最新プロセッサにおいても R→R, W→W, R→W の
順序が変わらないことは保証されているはずなので、
lfence, sfence命令は不要だと思います。

*fence命令が必要なのはMTRRやPATでキャッシュタイプをいじった場合や
Non-temporal store命令を使用した場合などであり、
C言語で普通に記述されたコードでは考慮しなくてよいのではないでしょうか。
2008-06-19 木 01:01:17 | URL | yamasa #- [ 編集]

リンク貼ってあるScott Meyersさんのパワポはもう読みました?
あと、上記の順序が変わらないという話は他プロセッサからみた可視・不可視の話が考慮されていないのでマニュアルの読み方が浅いと思いますよ。
2008-06-19 木 03:32:12 | URL | kosaki #- [ 編集]

> 上記の順序が変わらないという話は他プロセッサからみた可視・不可視の話が考慮されていないのでマニュアルの読み方が浅いと思いますよ。
Software Developer's Manual の
7.2.3.2 Neither Loads Nor Stores Are Reordered with Like Operations
7.2.3.3 Stores Are Not Reordered With Earlier Loads
あたりの記述はまさに「他プロセッサからみた可視・不可視の話」ですよね。
これを読んだ結論が、先のコメントです。
2008-06-19 木 04:55:27 | URL | yamasa #- [ 編集]

おおっと、失礼。
読んだ上で言ってるなら僕が間違ってるかもしれないので、ちゃんと調べなおしてから答えますわ。

ただ、現在マニュアルが見れる環境にないのと、ちょっと時間がとれないので、ちょっと遅くなるかもしれないっす。


2008-06-19 木 08:34:02 | URL | kosaki #- [ 編集]

ふむ。興味深い事が分かった。

IA32のマニュアル(手元にあるのは2006年1月版)だと

1. Reads can be carried out speculatively and in any order.

とあるが、Intel64 and IA32マニュアル(ようするに最近のやつ)だと

・Reads are not reordered with other reads.

とあるので、yamasaさんが正しそうな感じ。
しかし、時代と共にメモリオーダは緩くなっていく一方だと思っていたのに、
IntelはP6, Pentium4にさかのぼってメモリオーダ規則を厳しくしたのね。

#マニュアルが後から直せるということは、実装とマニュアルが合ってなかったんだろうけど。


眠いので嘘を言っているかもしれないので、明日、再調査しよう。
2008-06-19 木 09:36:52 | URL | kosaki #- [ 編集]
  1. 無料アクセス解析
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。