1 名前:デフォルトの名無しさん mailto:sage [2009/09/21(月) 17:19:27 ] マルチスレッドプログラミングについて語るスレ ■前スレ マルチスレッドプログラミング相談室 その7 pc12.2ch.net/test/read.cgi/tech/1215253576/ ■過去スレ その1 ttp://pc3.2ch.net/tech/kako/997/997345868.html その2 ttp://pc5.2ch.net/test/read.cgi/tech/1037636153/ その3 ttp://pc8.2ch.net/test/read.cgi/tech/1098268137/ その4 ttp://pc8.2ch.net/test/read.cgi/tech/1130984585/ その5 ttp://pc11.2ch.net/test/read.cgi/tech/1157814833/ その6 ttp://pc11.2ch.net/test/read.cgi/tech/1187008532/ OS・言語・環境は問わないが、それゆえ明記すべし。 テンプレ 【OS】 【言語】 【実行環境】 【その他特記する事項】
117 名前:デフォルトの名無しさん mailto:sage [2009/10/01(木) 23:01:29 ] だから、その命令の中に、lock xadd とかの重い命令があるんだよ。
118 名前:デフォルトの名無しさん mailto:sage [2009/10/01(木) 23:10:26 ] コンテキストスイッチが無いから速い、とか アセンブラで10数命令だから、とか 偉そうな態度の割に、底が浅すぎる。
119 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:06:49 ] お前も相当えらそうだが。
120 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:26:57 ] 無知が知ったかぶって偉そうにしながら恥を晒してるのとは違うみたいだけど。
121 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:44:09 ] 間違っているというだけで何が間違っているか書かないやつは大抵ハッタリだわな。
122 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:44:47 ] >>121 それ正解。
123 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:49:28 ] void __stdcall trylock(volatile int *spin) { __asm { mov ecx, spin; mov edx, 1; xor eax, eax; lock cmpxchg [ecx], edx; } } void __stdcall unlock(volatile int *spin) { __asm { mov ecx, spin; xor edx, edx; mov eax, 1; lock cmpxchg [ecx], edx; } } void __stdcall trylock_nlk(volatile int *spin) { __asm { mov ecx, spin; mov edx, 1; xor eax, eax; cmpxchg [ecx], edx; } } void __stdcall unlock_nlk(volatile int *spin) { __asm { mov ecx, spin; xor edx, edx; mov eax, 1; cmpxchg [ecx], edx; } } void __stdcall unlock_nbl(volatile int *spin) { *spin = 0; }
124 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:50:21 ] DWORD readtsc() { DWORD v; __asm { rdtsc; mov v, eax; } return v; } int main() { const COUNT = 1000; CRITICAL_SECTION cs; InitializeCriticalSection(&cs); volatile int spin = 0; int st = readtsc(); for (int i = 0; i < COUNT; ++i) { EnterCriticalSection(&cs); LeaveCriticalSection(&cs); } printf("%u clocks at %s\n", readtsc() - st, "CriticalSection"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock_nlk(&spin); unlock_nlk(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS(lockプリフィックス無し)"); st = readtsc(); for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock_nbl(&spin); } printf("%u clocks at %s\n", readtsc() - st, "CAS(movでunlock)"); }
125 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:51:21 ] ほれ、ベンチ用意したぞ。 シングルスレッドで、ロック獲得が必ず成功する場合の数字のみ。 実際はカウンタ持ってるから単純なcmpxchgじゃなくxaddで正負と0を駆使して判定してるだろうし ロックを獲得できなかった場合にブロックに移行する処理もあるだろうけどな。 まあ見難いが、面倒くさかったから TABのインデントは見たい人が自分でやってくれ。
126 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:54:44 ] これでもまだ「コンテキストスイッチが」「命令数が」と言いたいなら ご自由にどうぞ。
127 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 00:58:52 ] 乙 しかしお前がどのレス書いたやつで何を主張したいのかがわからん。
128 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 01:03:20 ] 実行してみなきゃ結果の意味するところもわからんからね。 まあ俺は>>112 >>115 >>117 とかだが。 関係ないが、stdcallとか、全然意味なかったな。 全部展開されてるし。 しかも、Enter/Leaveもレジスタにコピーされてレジスタ間接コールになってる。
129 名前:128 mailto:sage [2009/10/02(金) 01:04:01 ] >>123-124 が俺な。
130 名前:128 mailto:sage [2009/10/02(金) 01:27:59 ] まあ一応、俺の手元での数字を出しとく。 rdtscで計ってるので、別プロセスに割り込まれない限り 何回やっても似たような数字になる。 18065 clocks at CriticalSection 39098 clocks at CAS 13700 clocks at CAS(lockプリフィックス無し) 19025 clocks at CAS(movでunlock) 1番上が、単純にCriticalSectionをEnter/Leaveしたもの。 次が、「教科書通り」のCAS(lock+cmpxchg)を使ったスピンの取得と解放。 おそらく、>>111 もこれに似たコード(取れない時のループは無し)を書いたと思われる。 3番目は、上のコードから、バスロックを除いたもの。バスロックのコストを示すため。 4番目が、>>112 に述べた、unlock時のバスロックを避けるようにしたもの。 結論としては、>>112 の推測が確信に変わっただけ。
131 名前: ◆0uxK91AxII mailto:sage [2009/10/02(金) 11:18:35 ] spinlockの話題>>111 が、CASにすり変わっている件について。
132 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 12:33:54 ] 「教科書通りのスピンロック」って、普通は xchg (test-and-set)でロックを取って、movでアンロックじゃねーの? それとも最近の教科書は test-and-set より先に compare-and-swap を教えるのかな?
133 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 13:15:17 ] 一般のプロセッサでxchgが1バスサイクルで実行される保証なんて無い。 というより、普通は読みと書きになる。(x86が特殊なだけ) だから、ロックを取得するにはCASが必要。
134 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 13:17:13 ] あ、ごめん TASならば確かにCASである必要は無いね。
135 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 13:22:36 ] だけど、「アンロックがmovが普通」は違う。 理由は ja.wikipedia.org/wiki/%E3%82%B9%E3%83%94%E3%83%B3%E3%83%AD%E3%83%83%E3%82%AF#.E6.9C.80.E9.81.A9.E5.8C.96 のように、 movだと、直前のクリティカルな部分への書き込みが他のプロセッサに伝わる前に アンロック処理のmovの書き込みが他のプロセッサに伝わる可能性があるため。
136 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 13:52:10 ] >>135 それはメモリバリアの問題であって、movかCASかは関係ない。 mov命令がreleaseメモリバリア効果を持っていればそれで十分だし、 逆に>110で挙げたようなメモリバリア無しCAS命令では不十分。
137 名前: ◆0uxK91AxII mailto:sage [2009/10/02(金) 13:54:13 ] >>135 それはspinlockを使う側が考慮する問題であって、 作る側は無視して良い。
138 名前: ◆0uxK91AxII mailto:sage [2009/10/02(金) 13:59:49 ] W2kSP4, Athlon 64 X2 3800+, VC6SP6+PP5, 最適化無し 50239 clocks at CriticalSection 49180 clocks at CAS 21132 clocks at CAS(lockプリフィックス無し) 32103 clocks at CAS(movでunlock)
139 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 14:24:08 ] >>136 それがメモリバリアの問題だっていう、そんなことわかってるよ。 そして、「一般的なmov」はメモリバリアの機能など持っていない事 さらに、「(次に書く)このスレで"一般に"用いられるCASという用語」はメモリバリアを持っているもね。 もちろん、CASというのがメモリバリアとは直接は関係ないってことだって充分知ってるよ。 (そうでなければ、lockなしのcmpxchgなんてもの出すわけ無いだろ) だけどこのスレで一般的にCASと言ったら 「アトミック操作で用いる事が可能なCAS」のことが普通だろうに。
140 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 14:28:11 ] 「一般的なmov」つまり、普通のロード/ストア操作はメモリバリアを持っていないのだから 普通のスピンロックの実装では、アンロック処理に movではなくメモリバリアを持ったTASやCASを使う。 (それらはロック獲得処理の段階で存在が示されている) だから「普通はmovでアンロック」などということは有りえない。
141 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 14:37:59 ] >>140 は「教科書では」ね。
142 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 14:53:16 ] Windows Vista 64bit SP1, Core2DuoE6750, Microsoft Visual Studio 2008(VC Version 9.0.21022.8 RTM) /O2 /Ob2 /Oi /Ot (実行速度で最適化、インライン関数は展開可能な関数すべて展開) 101192 clocks at CriticalSection 67904 clocks at CAS 20424 clocks at CAS(lockプリフィックス無し) 88688 clocks at CAS(movでunlock) /Od /Ob1(最適化なし、インライン関数は展開しない) 108568 clocks at CriticalSection 99976 clocks at CAS 24184 clocks at CAS(lockプリフィックス無し) 65280 clocks at CAS(movでunlock) >>130 の結果が謎すぎる
143 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 15:17:56 ] >>139 アトミック性とメモリバリアは別の概念だぞ。 CASがアトミックなのは当たり前であり、俺もそんなことに 文句をつけているわけじゃない。 x86におけるlockプレフィックスのないcmpxchgは SMP環境ではアトミック性が保証されないから (正しい意味での)CASとは言えない。 でも、>110で挙げたのは「アトミック性は保証されているが メモリバリア効果を持たないCAS」だ。 CASとは「あるメモリ位置に対する内容の取得・比較から代入までが アトミックに行える操作」であり、メモリバリア効果、つまり 「前後の命令との間でリオーダーを行わないという保証」は必須ではないと 俺は言っている。 # 実際に、C++0xのatomicライブラリではそのように定義されているし。 「普通のロード/ストア命令はメモリバリアを持たない」と言うのなら、 メモリバリアを持つロード/ストア命令を定義して、それを使えばいい。 何故わざわざCASやTASのような複雑な操作を持ち出す必要がある? ちなみに、x86のmov命令は(初期のバグ持ちプロセッサを除いて) デフォルトでreleaseメモリバリア効果を持っているぞ。
144 名前:デフォルトの名無しさん mailto:sage [2009/10/02(金) 15:36:13 ] はいはいごめんよ。 全部俺が悪かったよ。
145 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 09:36:48 ] ttp://d.hatena.ne.jp/bsdhouse/20090720/1248085754 ここが勉強になった。
146 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 10:16:52 ] ちらっと見ただけなんだけど、「volatile つけた変数に排他性は無いよ」 ってことをグダグダ言ってるみたいだけど、そんなの当たり前では? 都市伝説もくそもねーよ
147 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 11:06:13 ] acquire/releaseバリヤって、 「そのスレッドでのメモリアクセスについて」限定? ↑のスライドだと前後の命令を・・・となってるけど
148 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 11:36:54 ] 当たり前よ っつかどういう意味で聞いてる?
149 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 11:37:10 ] 菊池バリヤー!
150 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 16:40:11 ] 「バリア」って概念には 「メモリアクセスがコーダーが記述した”順”に実行されることが 保証される」っていう以上のものは含まれていない(例えばインク リメント操作がアトミックになることまでは保証されない)と認識し ているのですが。当たってます? ネットに散らばっている情報にはブレがあると思えるし、正直、 勉強不足ではっきりと分からないところがあるので質問します。
151 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 18:09:38 ] >>150 それで正しい。 ちなみに、マルチスレッドの世界には「バリア同期」っていう全然別のものもあるので、 メモリバリアのことは「メモリフェンス」と呼ぶようにした方がいい。
152 名前:デフォルトの名無しさん [2009/10/03(土) 19:15:56 ] >>151 ありがとうございます。頭の中がすっきりしました。
153 名前: ◆0uxK91AxII mailto:sage [2009/10/03(土) 21:22:33 ] どうでも良い事だけど。 spinlockを奪い合った場合、 先に取ろうとした方が取れず、 後から取ろうとした方が取れたとしても、 動作としては正しいんだよね。
154 名前:デフォルトの名無しさん [2009/10/03(土) 21:37:43 ] spinlockはアンフェアだからそれで正しいね。
155 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 22:29:57 ] >spinlockはアンフェアだからそれで正しいね。 それは答えになってるのか??
156 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 23:21:32 ] 間違いではない=正しい という論理がわからないのか? どうしょうーもねーな
157 名前:デフォルトの名無しさん mailto:sage [2009/10/03(土) 23:32:43 ] 正しいのか?って言ってんじゃなくて 答えになってるのか? って言ってんだけど。
158 名前:デフォルトの名無しさん mailto:sage [2009/10/04(日) 00:51:01 ] 答えにはなっているように見える。「正しいのか?」という問いに「正しい」と答えている。 その答えが正しいのかどうかは別の話。
159 名前:デフォルトの名無しさん mailto:sage [2009/10/04(日) 03:29:21 ] ja.wikipedia.org/wiki/%E3%83%99%E3%83%B3%E5%9B%B3
160 名前:デフォルトの名無しさん mailto:sage [2009/10/05(月) 13:09:01 ] >>155 説明になっているかどうかはともかく 答えにはなっていると思うんだが。
161 名前:デフォルトの名無しさん mailto:sage [2009/10/13(火) 02:20:13 ] 火元の人 やり方が理解できない質問者 俺に分からないならこのスレにも理解できる奴いないんじゃね、とか思っていて、 それが態度にも滲み出ている 煽る人 分かってるつもりだけど分かってないで煽り続ける こいつを見た火元は「やっぱり分かってる奴いないんじゃないか」と思いこむ 住人タイプA 一目で分かるがお前の態度が気に入らないしコード示すのマンドクセ つーかこの説明で分かれボユゲ 住人タイプB みんな何言ってんだかわかんね ちょっと違うけどこのパターンに似てる
162 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 09:48:32 ] posix準拠のオーソドックスなやり方しかしない俺にはこのスレは不要なようだ おまえら何言ってるかわかんねぇーしw
163 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 10:36:30 ] >>162 自分からPOSIXスレッドとかに関連したネタをふればいいんじゃないかな? まあ正直なところ、ここは相談室スレなんだから、あまりにもハードウェア寄りな専門知識が 必要な話題については、できれば「並列化について語る」スレで熱く語ってくれって感じはしてる。 あっちはハード(マルチプロセッサ/マルチコア)全然オケーなスレなんだから。
164 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 13:09:43 ] 単に自分の付いていけないレベルの話題を締め出したいだけに見える
165 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 13:35:03 ] ということにしたいだけにも見える
166 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 21:17:55 ] つーか俺はposix準拠な世界で生きてきたので。 おまえらよくposix非準拠な話題で盛り上がれるなーw
167 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 22:48:54 ] >>166 CASやメモリバリアなどはpthreadライブラリの実装者にとっても 必須の知識だよ。
168 名前:デフォルトの名無しさん mailto:sage [2009/10/14(水) 23:10:22 ] >>167 利用者にとっては?
169 名前:デフォルトの名無しさん mailto:sage [2009/10/15(木) 03:21:14 ] POSIX厨としか言いようがない
170 名前:デフォルトの名無しさん mailto:sage [2009/10/15(木) 08:47:16 ] >>169 POSIX使うのが普通じゃないの?
171 名前:デフォルトの名無しさん mailto:sage [2009/10/15(木) 13:13:35 ] pthreadにはアトミック操作が定義されてないから、 単なるカウンタのインクリメントでも いちいちロックしなきゃならんのが嫌だ。
172 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 00:37:47 ] なんでPOSIXで厨なんだよ(´・ω・`)
173 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 02:28:34 ] POSIXスレッド以外の話題ってだけで叩くなら完全に厨だろ
174 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 06:51:32 ] 他人を厨と決めつける人が厨に見える
175 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 08:03:36 ] 何でも鸚鵡返しすれば反論になると思ってるだろ
176 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 08:04:58 ] baka
177 名前:デフォルトの名無しさん mailto:sage [2009/10/16(金) 08:09:28 ] pthread地獄 part 2 pc12.2ch.net/test/read.cgi/unix/1166620307/ ここへ行けばいいのに
178 名前:デフォルトの名無しさん mailto:sage [2009/10/17(土) 03:19:26 ] /\ ┌┐ ┌┐ ___ ___ / __ \ /\ ..||.. /\ || ___ \\ \ / / .\ \ \ \ .||. / / ┌──┘└──、\\  ̄  ̄ / / .\ \ \/ .||. \/ └──┐┌─ 、| |__| / / ┌──┐.\ \ ┌───┘└───┐ .|| || ..\/ └┐┌┘ .\/ └───┐┌───┘ / / || ┌┘└┐ /\ .||. /\ / / / / └┐┌┘ / / .||. \ \ / / / / ┌─┘└─┐ \/ ..||.. \/ \/ / / └────┘ └┘ \/ ....、 ....................--------、, i~゙7 r‐ッ !゙゙.! ! ! : !―――;;;;;;''''''''ゝ ,,ノ゛ ._ / ./ .,! .,! ! ! .,..............! ヽ..........-、 | |./ / .l、,`''-./ ./ ! ! | | ――ーッ .iー''''''''i | | l'-‐゛ `゙ッ .ゝ、 .| | | ,! ./ ./ ! ! ../ .,! /.,r'"\,/ .!ー′ ./ .,! . / ./ | │ .,./ ./ ,..‐" / . / / ./../ ./ .l゙ .r'"./ ゝ/゛ : ,,-'゛./ .〈 / .'|,゙,゙,,,, " .`゛ ゙'''"
179 名前:デフォルトの名無しさん mailto:sage [2009/10/20(火) 15:39:31 ] その “全米” はグアム島を含むのでしょうか。
180 名前:デフォルトの名無しさん mailto:sage [2009/10/20(火) 19:08:01 ] グアム、どうなんだろ。州に昇格すればいいのに。まあ、しないだろうけど。
181 名前:デフォルトの名無しさん [2009/11/03(火) 00:02:53 ] スレッドを終了させるときは_endthreadexじゃなく そのままreturnでもいいのか?スタックの開放されない?
182 名前: ◆0uxK91AxII mailto:sage [2009/11/03(火) 00:28:01 ] 良い。 mallocで取ってきた領域をfreeしなくて良いのと同じくらいに。 スタックとやらは、_endthreadexとは無関係。
183 名前:デフォルトの名無しさん mailto:sage [2009/11/03(火) 00:59:57 ] freeしろよ
184 名前:デフォルトの名無しさん mailto:sage [2009/11/03(火) 01:16:04 ] スレッドに強くないのに書き込んでみる。 ttp://msdn.microsoft.com/ja-jp/library/hw264s73(VS.80).aspx >ただし _endthread または _endthreadex は、_beginthread や _beginthreadex の >パラメータとして渡されたルーチンからスレッドが戻ると自動的に呼び出されます。 ってことで、returnすれば問題ないかと。 どちらかというと >_endthread と _endthreadex によって、C++ デストラクタはスレッドで保留状態になり、呼び出されません なので、呼ばないほうが好ましいような。
185 名前: ◆0uxK91AxII mailto:sage [2009/11/03(火) 01:52:01 ] 182は無かった事にしてください。 んゆ。
186 名前:184 mailto:sage [2009/11/03(火) 14:42:55 ] スレッドに強い人に補強して欲しいのだけど、それとも184の認識で問題なし?
187 名前: ◆0uxK91AxII mailto:sage [2009/11/03(火) 17:34:11 ] Microsoft Visual Studio\VC98\CRT\SRC\THREADEX.C んゆ。
188 名前:デフォルトの名無しさん mailto:sage [2009/11/03(火) 17:55:09 ] 問題なし
189 名前:デフォルトの名無しさん [2009/11/03(火) 22:08:15 ] スレッド識別子って何なんだ? 何に使うの?
190 名前:デフォルトの名無しさん mailto:sage [2009/11/03(火) 22:25:48 ] 殺したり、止めたり。
191 名前:デフォルトの名無しさん mailto:sage [2009/11/04(水) 21:43:06 ] 他スレッドの変数の中身知ることってできないかな?
192 名前:デフォルトの名無しさん mailto:sage [2009/11/04(水) 21:55:11 ] メモリ空間は共有しているので、アドレスがわかれば普通に参照できる。
193 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 12:32:06 ] win32のインターロックをクリティカルセクションと 同じように使ったら早くて驚いた。 両者の内部的な違い・利点・欠点てなんですかね?
194 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 14:06:45 ] そもそも用途が違うんじゃない? インターロックは変数1個ぶんの更新しかできないでしょ? インターロックを使ってクリティカルセクションと同様のものを作ることはできるだろうし、 クリティカルセクションを使ってインターロックと同様のものを作ることもできるだろうけど、 そういう話?
195 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 14:31:15 ] インターロック一発で出来ることならインターロックで。
196 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 14:54:32 ] win32のクリティカルセクションは衝突しなければインターロックと同じくらい早いんだなこれが
197 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 16:01:33 ] いや倍くらいは遅いだろう。
198 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 16:15:02 ] んだ。インターロックで済むならそれが数倍早い。
199 名前:193 mailto:sage [2009/11/05(木) 19:29:23 ] 今以下のクラスでクリティカルセクションと同じように扱ってテストしてるんだ。 class InterLock { private: LONG m_Flag; public: void Enter() { while(InterlockedCompareExchange(&m_Flag,1,0)) Sleep(0); } void Leave() { InterlockedCompareExchange(&m_Flag,0,1); } public: InterLock() { m_Flag = 0; } virtual ~InterLock() { } };
200 名前:193 mailto:sage [2009/11/05(木) 19:30:08 ] こっちはクリティカルセクション晩 class CriticalSection { private: CRITICAL_SECTION cs; public: void Enter() { EnterCriticalSection(&cs); } void Leave() { LeaveCriticalSection(&cs); } public: CriticalSection() { InitializeCriticalSection(&cs); } virtual ~CriticalSection() { DeleteCriticalSection(&cs); } };
201 名前:193 mailto:sage [2009/11/05(木) 19:43:57 ] //グローバル変数 ロッククラス g_Lock; int g_i = 0; // 三つのスレッドで以下を走らせる void Run() { for(int i=0; i<10000000; i++) { g_Lock.Enter(); g_i++; g_Lock.Leave(); } } int main() { //3つのスレッドでRun()を走らせ、スレッド終了まで待機 (...省略) cout << g_i << endl; cout << time.result() << endl; return 0; } 結果 クリティカルセクション 35秒 g_i = 30000000 インターロック 5.5秒 g_i = 30000000 ロッククラス無し 0.16秒 g_i = 21203536(整合性無し) 環境 OS:win xp CPU:core2duo1.8G メモリ:3G
202 名前:デフォルトの名無しさん mailto:sage [2009/11/05(木) 20:42:07 ] ソースまともに見てないけど、CSがもしインライン化されないなら性能的には勝てない だろうしなぁ まぁ、asm読めば全て分かるだろうけど
203 名前: ◆0uxK91AxII mailto:sage [2009/11/05(木) 23:23:50 ] TryEnterCriticalSection ~ Sleepだとどうなるの、っと。 threadをCPUと1:1にbindしたらどうなるの、っと。 timesliceを変えたらどうなるの、っと。 結果は書かない方が良い。
204 名前:193 mailto:sage [2009/11/06(金) 07:01:38 ] >TryEnterCriticalSection ~ Sleepだとどうなるの、っと。 これだけやってみた。 上記のテストだとインターロックとの差は0.5秒内、 つまりほとんど差がなくなった
205 名前:デフォルトの名無しさん mailto:sage [2009/11/06(金) 13:00:12 ] プロセッサ数が2以上ならSpinWaitにしたらどうなる? あとインターロックのIncrementでダイレクトアップデートにしたらどうなる?
206 名前: ◆0uxK91AxII mailto:sage [2009/11/06(金) 20:26:47 ] 違うネタだけど。 #include <windows.h> #include <tchar.h> #include <stdio.h> #include <stdlib.h> #define THREADS 64 #define LOOPS 123456789 struct SData { LARGE_INTEGER m_cntBegin; LARGE_INTEGER m_cntEnd;}; DWORD WINAPI thread(LPVOID pArg); int __cdecl cmpForSort(const void *pArg0, const void *pArg1); int _tmain() { int i; HANDLE ahThread[THREADS]; SData aData[THREADS]; LARGE_INTEGER diff; for (i=0; i<THREADS; i++) ahThread[i] = CreateThread(NULL, 0, thread, &aData[i], 0, NULL); WaitForMultipleObjects(THREADS, ahThread, TRUE, INFINITE); qsort(aData, THREADS, sizeof SData, cmpForSort); for (i=0; i<THREADS; i++) { CloseHandle(ahThread[i]); diff.QuadPart = 0<i? aData[i].m_cntBegin.QuadPart - aData[i-1].m_cntBegin.QuadPart: 0; _tprintf(_T("thread: %d, diffBegin: %I64d, clock: %I64d\n"), i, diff.QuadPart, aData[i].m_cntEnd.QuadPart-aData[i].m_cntBegin.QuadPart); } return 0; }
207 名前: ◆0uxK91AxII mailto:sage [2009/11/06(金) 20:28:49 ] DWORD WINAPI thread(LPVOID pArg) { SData *pData; DWORD value; float sum; pData = (SData *)pArg; QueryPerformanceCounter(&pData->m_cntBegin); __asm { mov ecx, LOOPS fldz LOOP_: fadd QWORD PTR value dec ecx jnz LOOP_ fstp DWORD PTR sum } QueryPerformanceCounter(&pData->m_cntEnd); return 0; } int __cdecl cmpForSort(const void *pArg0, const void *pArg1) { LARGE_INTEGER diff; diff.QuadPart = ((SData *)pArg0)->m_cntBegin.QuadPart - ((SData *)pArg1)->m_cntBegin.QuadPart; if (0 > diff.QuadPart) return -1; if (0 < diff.QuadPart) return 1; return 0; }
208 名前: ◆0uxK91AxII mailto:sage [2009/11/06(金) 20:37:44 ] 同じ処理なのに所要時間がブレるとか、 先に開始したthreadよりも、後から開始した方が早く処理を終えるとか。 そういうのが起こりうる。 computer gameでmulti threadの利用に消極的な理由の一つだと思う。
209 名前:193 mailto:sage [2009/11/06(金) 23:12:33 ] >>205 >インターロックのIncrementでダイレクトアップデートにしたらどうなる? 1.3秒だった >SpinWait これC#じゃん
210 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 01:40:37 ] スピン待機はC#限定じゃなく一般的な概念だ
211 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 09:40:03 ] スピンすると余計遅くなりそうだな。 一般的な使用状況に比べて処理と競合がタイトすぎるせいかな多分。
212 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 09:45:49 ] ああつまり3スレッド同時じゃなくて1スレッドで3回繰り返した方が速いとかっていう状態ね。
213 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 17:33:40 ] あーいやいや、これだとちょっと書き方がおかしいな…まあいいや
214 名前:193 mailto:sage [2009/11/07(土) 19:49:07 ] スピンロックは信頼性がないという話を聞いたような。 さて上記のベンチですが、1スレッドで3回繰り返したほうがずっと早いです。 衝突したときに別の処理をせずに待つ場合はシングルスレッドにした方がいいかも。
215 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 20:02:47 ] スピンロックに信頼性が無かったらどうすんだよw 全然仕組みとか分かってなくて使ってる匂いがぷんぷんするな
216 名前:デフォルトの名無しさん mailto:sage [2009/11/07(土) 20:03:53 ] スピンロックとスピンウェイトは基本的に別物です。
217 名前:デフォルトの名無しさん mailto:sage [2009/11/08(日) 00:12:02 ] それと信頼性に何の関係が?