07/03/04 08:20:53
>>268
>>261はいろいろ省略してるのだけど、InterlockedCompareExchangePointerを使えといってるのだと思うよ。
>Cで書いた場合のコードに、>>255と本質的な違いがあるのか?と
>問いたかっただけです。
どちらも遅延初期化で本質的な違いはなさそうだけど、
>>261はダブルチェックロッキングが正しく出来ているが>>255には穴がある。
272:259
07/03/04 08:27:12
>>269
理解しましたm(_ _)m
他スレッドのInterlockedExchangePointer()によって値が変えられていたら
deleteするという意味なのですね。
Cで書くと
static CRITICAL_SECTION *p = 0;
if (!p) {
CRITICAL_SECTION *q = malloc(CRITICAL_SECTION);
InitializeCriticalSection(q);
InterlockedExchangePointer(&p, q);
if (p != q)
free(q);
}
でしょうか。
273:259
07/03/04 08:30:03
んが。
malloc(sizeof(CRITICAL_SECTION));
ですね。
それと。InterlockedExchangePointer()ではなく、
InterlockedCompareExchangePointer()を使わなければならないのですか。
むずかしい...。
274:259
07/03/04 08:32:30
>>271
>>255のコードの穴というのは、>>259に書いたのとは別のものでしょうか。
275:デフォルトの名無しさん
07/03/04 09:21:12
あーそうか、ほんとごめん。
確かに>>271の通り、CompareExchangeの方のこと(つまり>>258が俺の凡ミス)。
俺が重要な部分を間違えていたのに、意図を理解してくれる人がいてくれて助かった。
他の人も含め、ごめんね。
>>259では、本質的な解決にならないと思うよ。
つまり、比較(テスト)と初期化(&代入)の間に他のスレッドに割り込まれる可能性を消すには
atomicなCASを実行するしかないって事。
276:デフォルトの名無しさん
07/03/04 09:31:57
あ、そうか、>>255を見るとInterlockedを使っているのか。
でも、InterlockedIncrementは正負と0しか判定できないんじゃなかったかな。
で、仮に
初期値を-1として
2^32個以上のスレッドが同時に初期化部に入ることは有りえないとして
>>259の修正(Inc失敗なら他のスレッドを待つ)を加えて
当然volatileにして
とすれば、正常に動くのかな。
でもそこまでするなら、やっぱりCASを使う方がまともかと。
277:259
07/03/04 09:40:12
>>276
はい。CAS方式がエレガントでまともなコードであると納得できました。
Sleep()ループで待つなんてカッコ悪いことは出来ればしたくありません...。
有難うございます。
278:デフォルトの名無しさん
07/03/04 09:45:22
ここまでやれば大丈夫だと思うけど。
if (!initialized)
if(InterlockedIncrement(&lock) == 1) {
pthread_mutex_init(&mutex, 0);
initialized = 1;
メモリバリア~~
} else {
while (!initialized) {
Sleep(1);
メモリバリア~~ またはinitializedが揮発性であることが必要
}
}
}
老婆心から言えばスレッド生成前までに作っておいたほうがよいと思う。
スレッド生成後の初期化なんてバグの元。
PTHREAD_MUTEX_INITIALIZERマクロが何をやってるか調べてみたら何かヒントがあるかもしれないね。
javaで有名になったダブルチェックロッキングの話はまだ半分くらいしか理解できてないしなorz
279:デフォルトの名無しさん
07/03/04 09:47:50
InterlockedIncrementはWin95以前だと正負と0の判定しかできないので>>255のようには使えないよね。
あと厳密に言えばの話だけど
このスレの上のvolatile関連の議論からするとinitialized=1;の変更がキャッシュのせいで
他のスレッドに伝わらないかもしれない(規格的には)ので>>255のinitializedにはlock命令が必要だけど
lock命令を追加しようとすると結局>>261みたいになってしまうんじゃないかな。
別に言わなくてもわかるだろうけど
>>255は volatile static int lock = 0;
>>272は
volatile static CRITICAL_SECTION *p = NULL;
if (p != q) { DeleteCriticalSection(q); free(q); }
280:デフォルトの名無しさん
07/03/04 09:49:12
> PTHREAD_MUTEX_INITIALIZERマクロが何をやってるか
これはさすがに定数値を{}なりで囲んでるだけだと思うけど。
Cでも使えるんだし。
281:259
07/03/04 09:52:14
PTHREAD_MUTEX_INITIALIZERは単に{ 0 }
とかだと思います。
>>279
うわ。赤面しまくりです...。
ぶっちゃけUnixベースのライブラリをちょろっといじくってWin32に
移植しようと思っただけなのですが、こんなワナが待っていたとは
思ってもいませんでした。
282:デフォルトの名無しさん
07/03/04 10:24:41
下の例の場合変数iにvolatileは必要かどうか質問です。
lock, unlockがメモリバリアだから必要ないという認識なのですがつけている例も見ます。
>>261だとlockせずに読んでる箇所もあるので必要なのかもしれませんが、
この辺の基準ってどうされていますか?
int i;
thread_function() {
mutex.lock()
i = i + 1;
mutex.unlock()
}
283:デフォルトの名無しさん
07/03/04 10:32:03
だれか
.NET Frameworkのメモリモデルとかに詳しい人おらんかね?
284:デフォルトの名無しさん
07/03/04 10:42:25
>>282
付けといた方がいいんじゃない?mutexのメモリバリアでcpuキャッシュの同期は取れても
スタックやレジスタに積まれたままだったら意味ないしね。
285:デフォルトの名無しさん
07/03/04 11:17:03
>>283
設計上はウィークメモリオーダリングということなので、OoOあり~の、コヒーレンシキャッシュは信用できね~のです。
今のところ実装上はx86系のWindows上ではストロングメモリオーダリングのみ。
Itaniumは構成によってウィークメモリオーダリングもある得るそうです。
286:デフォルトの名無しさん
07/03/04 11:51:52
ところが、CLR2.0では書き込みオーダは保証されてて、
今後もそうだと約束されてるらしい。
それはおいといて、よく理解できてないのが、
書き込みスレッドでメモリバリアを実行した場合、
読み込み前のメモリバリアは必要なのかどうか。
あるメモリ領域に書き込みしてメモリバリア実行、その後完了フラグセット。
別スレッドで完了フラグを確認してからメモリ領域を読み込みってときに、
完了フラグ確認後にメモリバリアは必要なのかどうか。
なんとなく読み込み順が保証されないから必要な気もするんだが、
.NETのメモリバリア命令はフルメモリバリアだから不要?ってのも見た。
.NETのメモリバリアは別プロセッサの読み込みキャッシュもクリアして
かつJITの最適化とかで先読みとかがおこらないなら大丈夫なんだと思うんだけど
この方面素人なのでいまいちよく分からない。
287:デフォルトの名無しさん
07/03/04 11:53:25
メモリバリアの説明には、このプロセッサ上でキャッシュをフラッシュするとかって説明になってんだよね…
288:デフォルトの名無しさん
07/03/04 13:04:32
Itaniumだと、そもそもout of orderしないですな。
命令の並べ替えや並列化はすべてコンパイラの仕事だ。
289:デフォルトの名無しさん
07/03/04 13:11:11
だからこそ その辺の事情は本来プログラムで意識したくないよな・・・
DCLの欠点なんて最たるものだし
290:デフォルトの名無しさん
07/03/04 17:17:43
>>282
メモリバリアだから必要ないという認識では、ちょっと違うね。
関数呼び出しをまたいでグローバル変数をキャッシュできないから
volatileが必要ないというのが本質。
変数をレジスタ等にキャッシュしていないからこそ、メモリバリアが有効になる。
仮にlockやunlockをインライン展開できるようなコードで実装できたとすると
while() { lock(); i = i + 1; unlock(); } はvolatileが無いと危険かもしれない。
291:デフォルトの名無しさん
07/03/04 19:41:48
>>290
それは本質じゃなく単なる実装の話だと思います。
たとえばmsvc++などは次の理由からそういう実装になっています。
現在のx86系WindowsはOoOはやっててもアプリからは見えないハード的な仕掛けになっていますし、
コヒーレントキャッシュもある前提なのでキャッシュによる不整合もありません。
x86はレジスタの数が少ないので関数呼び出しのタイミングで変数をメモリ上に書き出します。
たとえばpthreadのmutexではvolatileは不要とドキュメントにあります。
すべてのコンパイラがそうなってるかどうかは分かりませんが、少なくともスレッド系のライブラリと一体で
提供されている環境ではサポートされているはずです。
292:デフォルトの名無しさん
07/03/04 20:23:08
>>291
インライン展開できない関数を呼ぶ前は、x86であろうと無かろうと
非ローカル変数をキャッシュできないよ。
レジスタの数が問題なのではなく、非ローカルな変数は呼び出した先で
更新される可能性があるから。
293:デフォルトの名無しさん
07/03/04 21:03:48
あと、ローカル変数でも、アドレスを取って他の関数に渡している場合に
その前と後で変数の中身が変更される可能性は、コンパイラも考慮しているはず。
だから例えば>>255のlockや>>272のpにはvolatile不要なはず。
もちろん、>>255のinitializedには必要だけどね。
で、pthread_mutex_tも、アドレスを取って渡すのだからvolatile不要、
という考え方でも充分かもしれない。
ただし、アドレスを取って呼び出した関数から戻った後に
変数の中身が他のスレッドによって変更される可能性は考慮されないので
レジスタにキャッシュされるかもしれない。
それが問題になる可能性がある(コードで中身を参照している)ならば
volatileが必要になるね。
294:デフォルトの名無しさん
07/03/04 21:29:48
>>292
確かにそこは例えが悪かったので取り消します。
(PGOのような広域のインライン展開のことを考えていたのですが論旨に合わないようです)
言いたかったのは同期関数の呼び出しのタイミングで
偶然レジスタとメモリの同期が取られているという話ではなく、
メモリバリア実現の属性のひとつとして関数の呼び出し時にレジスタとメモリの同期が
とられるという仕組みが利用されてるということです。
だから、レジスタとメモリの同期以外にCPUキャッシュ間の同期やOoOの調整が必要ならば
その処理が同期関数に含まれていなければならないと考えているわけです。
295:デフォルトの名無しさん
07/03/05 18:53:41
____
/ \
/ ─ ─\
/ (●) (●) \馬鹿ばっか
| (__人__) |
\ ` ⌒´ /
ノ \
/´ ヽ
| l \
ヽ -一''''''"~~``'ー--、 -一'''''''ー-、.
ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒))
296:デフォルトの名無しさん
07/03/05 22:57:17
volatile旋風スゴス
297:デフォルトの名無しさん
07/03/10 22:35:07
質問です。
while ( count > 1 ){
pthread_cond_wait( &cond_t, &mutex );
}
この場合、条件変数と呼ばれるものはcountですか?
それともcond_tになるのでしょうか?
また、countのチェックにifは使ってはならない。と言われたのですが、
なぜだか解りません。
上記の部分と、
while (1){
if( count > 1 ) pthread_cond_wait(ry);
}
は同じだと思うのですが・・・
よろしくお願いします
298:デフォルトの名無しさん
07/03/10 22:51:41
>>297
while (1)
{
if( ! (count > 1) ) break;
pthread_cond_wait(ry);
}
と同じだと思う。
299:デフォルトの名無しさん
07/03/10 23:04:21
>>298
そうでした。すんません
300:デフォルトの名無しさん
07/03/10 23:33:31
> 条件変数と呼ばれるものはcountですか?それともcond_tになるのでしょうか?
条件変数はcond_t。!(count>1)は述語。
> countのチェックにifは使ってはならない。と言われたのですが、
言った本人に聞けばいいと思う。いけないってことは無いと思う。
pthread_mutex_lock(&mutex);
while (!pred(ry))
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
というのが定型パターンの予感はするんで、
その人にとって奇怪なコーディングするなという意味かもしれん。
301:デフォルトの名無しさん
07/03/11 08:33:14
ありがとうございます。
countは述語っていうのですか。知りませんでした。
>ifでんでん
後でもう一度聞いてみます。
302:デフォルトの名無しさん
07/03/11 11:25:05
でんでんってなんだ。云々(うんぬん)と言いたいのか、わざとボケてるのかどっちだ。
303:デフォルトの名無しさん
07/03/11 12:35:43
>>302
単なる2chのジャーゴンだから気にするな
304:デフォルトの名無しさん
07/03/11 14:17:43
countが述語なんじゃなくて
"count>1"が述語
countは単なる変数
305:301
07/03/11 15:38:51
>>304
"count>1"で、述語。ですか。解りました。
ありがとうございます。
>>でんでん
"うんぬん"で"云々"ですか。初めて知りました
ゆとり年代より一つ上なはずなんだけどゆとりでごめんなさい
306:300
07/03/11 15:43:08
ごめん。!(count>1)でなく、count>1だった。
301に幸あらんことを。
307:デフォルトの名無しさん
07/03/11 15:43:39
俺がかつて1日だけ流行らそうとしてばら撒いてたでんでんが意外な影響を。
308:デフォルトの名無しさん
07/03/11 16:04:43
「云々」を「でんでん」ってことは
「云」を「でん」と読んでるって事だよな。
俺、そもそも「云」という漢字、単独でどう読むか知らないのだが。
309:デフォルトの名無しさん
07/03/11 16:29:44
>>308
「ウン」でしょ。
310:デフォルトの名無しさん
07/03/11 16:37:38
伝が“でん”だからなあ
311:デフォルトの名無しさん
07/03/11 20:45:06
雲が「うん」と読まれることには頓着しないらしい。
312:デフォルトの名無しさん
07/03/11 22:22:20
ワンタン
雲呑
313:デフォルトの名無しさん
07/03/12 00:36:16
うーんぬんむーしむし、かーたつむりー
314:デフォルトの名無しさん
07/03/16 09:25:59
____
/ \
/ ─ ─\
/ (●) (●) \ 「テラワロスwwwwwwwうぇうぇwwww」・・・・と
| (__人__) | ________
\ ` ⌒´ ,/ .| | |
ノ \ | | |
/´ カタ. | | |
| l カタ | | |
ヽ -一ー_~、⌒)^),-、 | |_________|
ヽ ____,ノγ⌒ヽ)ニニ- ̄ | | | ____
315:デフォルトの名無しさん
07/03/20 00:12:35
ごめん書籍いいでしょっていわれてるけれど
マルチスレッドの勉強する本をおしえてほしいの
316:デフォルトの名無しさん
07/03/20 00:32:02
マルチスレッドについて本で得られるものは1%もない。
といっては見もふたもないので、もう少し具体的にマルチスレッドで何をしたいの?
OSは?マルチスレッドアプリ?APIがしりたい?それともカーネルの実装(はないよな)?
317:デフォルトの名無しさん
07/03/20 15:54:59
Unix 方面の人は「実践マルチスレッドプログラミング」
Win32の人は「Win32マルチスレッドプログラミング」
当り前のことが当たり前に書かれてるだけで、
別にいいも悪いもないけど。
このあたりに出てくるような概念、問題、手法については常識として理解した上で、
新しい手法やOS/CPU/言語毎のメモリモデルなどについての知識を深めると、
volatile 論議とかで無駄に遊べる。
318:デフォルトの名無しさん
07/03/20 23:15:04
>>315
Java使いなら↓は超オススメ。
URLリンク(www.amazon.co.jp)
邦訳版もあるよ。
319:デフォルトの名無しさん
07/03/21 00:27:18
>>317
素朴な疑問
> Unix 方面の人は「実践マルチスレッドプログラミング」
> Win32の人は「Win32マルチスレッドプログラミング」
この辺を読めば volatile 最強って言い切れるようになるんですか?
320:デフォルトの名無しさん
07/03/21 03:30:37
317をもう一度よく読んだほうがいいんじゃない?
321:デフォルトの名無しさん
07/03/21 04:34:08
自作自演の可能性
322:デフォルトの名無しさん
07/03/21 13:51:09
volatile厨を論破するのはそんなに簡単じゃないよ。
323:デフォルトの名無しさん
07/03/21 15:55:04
NG登録するだけだし
324:デフォルトの名無しさん
07/03/24 10:03:31
Win32の本ってオライリーのやつのことでいいの?
325:デフォルトの名無しさん
07/03/24 15:56:09
>>315
並行プログラミングの原理―プロセス間通信と同期への概念的アプローチ (単行本)
326:デフォルトの名無しさん
07/03/27 14:50:58
____
/ \ /\ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \ volatile厨を論破するのはそんなに簡単じゃないよ。
| |r┬-| |
\ `ー'´ /
___
/ \
クスクスッ /ノ \ u. \ !?
/ (●) (●) \
| (__人__) u. |
\ u.` ⌒´ /
____
/ \!??
/ u ノ \ クスクスッ
/ u (●) \
| (__人__)|
\ u .` ⌒/
327:デフォルトの名無しさん
07/03/27 22:33:12
Javaのsynchronizedとwaitとnotifyに関する質問なんだが
URLリンク(www.javaworld.jp)
ここの
class Buffer {
private int value;
private boolean isEmpty = true;
public synchronized void putValue(int v) {
while (!isEmpty) {
try {
wait();
} catch (InterruptedException e) { }
}
notifyAll();
isEmpty = false;
value = v;
}
public synchronized int getValue() {
while (isEmpty) {
try {
wait();
} catch (InterruptedException e) { }
}
notifyAll();
isEmpty = true;
return value;
}
}
これがどうして動くのか分からん。
あるスレッドがgetValueに入ってる間は、ほかのスレッドは
getValueにもputValueにも入れないんじゃないのか
328:デフォルトの名無しさん
07/03/27 22:34:13
すまんソースコードが見づらくなってしまった。
リンク先を見てくれ。
329:デフォルトの名無しさん
07/03/27 22:52:21
>>327
前のページで説明されてる。
330:デフォルトの名無しさん
07/03/27 22:53:08
URLリンク(sdc.sun.co.jp)()
の二段落目を理解できない無能?
331:デフォルトの名無しさん
07/03/27 23:05:42
すまんかった。
とんくす
332:デフォルトの名無しさん
07/03/28 08:53:09
____
/ \ /\ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \ の二段落目を理解できない無能?
| |r┬-| |
\ `ー'´ /
___
/ \
クスクスッ /ノ \ u. \ !?
/ (●) (●) \
| (__人__) u. |
\ u.` ⌒´ /
____
/ \!??
/ u ノ \ クスクスッ
/ u (●) \
| (__人__)|
\ u .` ⌒/