1 名前:デフォルトの名無しさん mailto:sage [2005/11/03(木) 11:23:05 ] マルチスレッドプログラミングについて語るスレ。 OS・言語・環境は問わないが、それゆえ明記すべし。 その1 pc3.2ch.net/test/read.cgi/tech/997345868/ その2 pc5.2ch.net/test/read.cgi/tech/1037636153/ その3 pc8.2ch.net/test/read.cgi/tech/1098268137/
196 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 01:53:34 ] HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)で作ったイベントに対して SetEvent(hEvent);←TRUEがかえる でも、その次に WaitForSingleObject(hEvent, 0)とやってもWAIT_OBJECT_TIMEOUTがかえる。 こういうことがおきているのですがどのようなことが考えられますか?
197 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 07:15:10 ] >>196 SetEventは成功したけど、イベントオブジェクトがシグナル状態になる前にWaitForSingleObjectがタイムアウトした。
198 名前:>>46 mailto:sage [2006/01/21(土) 09:16:54 ] >>196 他のスレッドが一生懸命 ResetEvent(hEvent) を やってる。
199 名前:196 [2006/01/21(土) 14:20:25 ] >>197 SetEventってシグナル状態にした後で戻るわけではないのですか? >>198 ソースを見る限りほかのスレッドが触ることはなさそうなのですが確信持てないです。 SetEventとWaitForSingleObjectの間で他のスレッドにスイッチしなければそういうことはおきないですよね? であれば確認のためにはスレッドのスイッチをSetEventとWaitForの間で抑制してあげればいいですよね。 なにか、任意のコードブロックではスレッドスイッチを禁止する方法はないでしょうか
200 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 14:26:18 ] ちょっと確認だが、WaitForSingleObject()の第二パラメータの0ってNoWaitだよな? 単に待てば委員で内科医?
201 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 14:42:02 ] >196のままのコードを実行してみたけど、ちゃんと0が帰ってきたよ。
202 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 15:04:56 ] >>199 >>196 の事象が事実であるなら、そういうものだと思って使うべき。 嫌なら別の手段を用いるべき。
203 名前:196 mailto:sage [2006/01/21(土) 15:47:24 ] >>200 SetEventしてそれが本当にシグナルになったかを見るためにWaifFor・・したのですが、 それがなぜかシグナルになっていないのです。 >>201 検証ありがとうございます。>>196 のままのコードだとそうなると思いますが、実際にはほかのスレッドもいるので 何が起きているかはよくわかっていません。(デバッガでステップ実行したりデバッグライトを入れるだけで動きが変わるため) とりあえず、月曜にほかのスレッドがResetしていないか確認したいと思います あとSetEventって非同期に動いたりしませんよね? SetEvent(hEvent); ここで誰かがResetEventしない限り下はTRUEにならないですよね? if(WaitForSingleObject(hEvent,0)==WAIT_OBJECT_TIMEOUT) { }
204 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 17:01:11 ] >>203 だから、WaitForSingleObject(hEvent, INFINITE)してみたら?
205 名前:デフォルトの名無しさん mailto:sage [2006/01/21(土) 21:15:12 ] そもそも、WAIT_OBJECT_TIMEOUTってなんだ? 成功:WAIT_OBJECT_0 or WAIT_TIMEOUT or WAIT_ABANDONED 失敗:WAIT_FAILED のいずれかが、WaitForSingleObject()の戻り値なんだが・・・ とりあえず、該当部分のコードを晒せ、晒したくなかったらコピペも満足にできない房は二度とくんな。
206 名前:>>46 mailto:sage [2006/01/21(土) 23:02:03 ] >>199 > ソースを見る限りほかのスレッドが触ることはなさそ > うなのですが確信持てないです。 はぁ? 悪いけど、変数がどっからアクセスされるか自信 が持てないなんて言う奴にはマルチスレッドプログラムは 無理だよ。あきらめたら? >>203 で、デバッガとか言ってるが君がやることは、デ バッガでプログラムを追っかけることではなく hEvent で全ソースに対して findstr することだと思う。 (そこらじゅうで hEvent 使ってるなら、問題のところ の変数名を変えるべき。) >>201 うちでも、CreateEvent() 〜 SetEvent() 〜 WaitForSingleObject() 〜 CloseHandle() を 10,000,000 回実行したが、WAIT_OBJECT_0 しか 返らないよ。 >>202 その考え方はおかしいだろ。 >>196 みたいな動きをするイベントなんて使い物にな らないと思う。
207 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 08:57:50 ] >>206 >>>196 みたいな動きをするイベントなんて使い物にな >らないと思う。 eventは許可するまで待たせておくことが目的の物だから、setは少しくらい遅れても良いと思う。 acquireI->releaseする同期モノのreleaseも同じ。
208 名前:>>46 mailto:sage [2006/01/22(日) 10:13:10 ] >>207 少しってどれぐらい? 1秒なの? 1ms なの? 1μs なの? 他のスレッドに対して set の伝播が遅れるのは問題ない けど、自スレッドに対して SetEvent() してからイベン トがセットされるまでの間に「隙間」があるのは問題。 例えば、 SetEvent(hEvent); // hEvent は、ワーカースレッドか処理終了でセットする。 StartWorkerThread(); // 処理開始指示。 while(WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT){ // 終了したか? // 終了してないなら、他のことしてようっと。 } (こんなプログラムは組むなと言う意見はまた別の機会に。) と言うプログラムがうまく動かない。 動かないだけなら、まだしも下手するとうまく動いたり動 かなくなったりすると言う最悪パターンになる。 マルチスレッドプログラムやるなら「隙間」をもっと意識 できないとはまるよ。
209 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 12:18:00 ] >>208 「こんなプログラムは組むな」
210 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 12:45:43 ] >自スレッドに対して SetEvent() してからイベン >トがセットされるまでの間に「隙間」があるのは問題。 いやだから、その隙間は無いんだって。 というか、先頭のSetEventはResetEventの間違いだよな、な。
211 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 16:13:56 ] スレ違いスマソ 下のスレでマルチコアについて侃侃諤諤の論争してるんですけど、 みなさんはこれからのマルチコア時代についてどう捉えていますか? Intelの次世代CPUについて語ろう 21 pc7.2ch.net/test/read.cgi/jisaku/1136822334/
212 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 17:12:45 ] >>208 次にタスクスイッチが起こったときにsetしてくれればいい程度に思って使ってるね、私は。 >while(WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT){ // 終了したか? 普通スレッド終了の検知はスレッドのハンドルをWaitForSingleObjectの引数にする。 わざわざeventなんて作らない。 スレッドをプールするなんて言い訳は聞かない。 >>211 面倒なことはOSに任せて今まで通りにやる。
213 名前:>>46 mailto:sage [2006/01/22(日) 20:04:17 ] >>210 すまん、勘違いだ。 セット側はさすがにちょっと考えにくいな。 (まあ、リセット側も無理矢理だが。) ただ、セット側とリセット側で挙動が違うのはちょっと気 持ち悪い。 >>211 マルチコアって言ったって、マルチプロセサの一形態だろ。 別に何か変えないといけないのか? 専用のチューニングが必要になったらそのとき勉強するよ。 >>212 > 普通スレッド終了の検知はスレッドのハンドルを > WaitForSingleObjectの引数にする。 スレッドの終了 ≠ 処理の終了 誰も、スレッドの終了の検知方法なんて聞いてないぞ。 最近知ったので、知ったかしたくなったのか?
214 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 20:06:09 ] さーしったかしったかたーこうりんだー さーしったかしったかたーこうりんだー みぎあしくんひだりあしくん
215 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 20:17:49 ] >>214 気が済んだか? すっきりしたら、違うスレに行ってくれよな。
216 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 20:27:26 ] >>213 >スレッドの終了 ≠ 処理の終了 そういうことを言いたかったのか。
217 名前:デフォルトの名無しさん mailto:sage [2006/01/22(日) 21:08:07 ] VC6.0でスレッドを生成するために、 _beginthreadexを使おうと思っていますが、 1プロセスあたりに生成できるスレッド数って 決まっているのでしょうか? MSDNのCreateThreadのヘルプには、 2028との数字がありますが・・・
218 名前:デフォルトの名無しさん mailto:sage [2006/01/23(月) 00:53:27 ] スタック用のメモリ領域が1MB確保されるんじゃなかったかな
219 名前:デフォルトの名無しさん mailto:sage [2006/01/23(月) 00:57:58 ] そんなにスレッド作ってどうするの?
220 名前:デフォルトの名無しさん mailto:sage [2006/01/23(月) 22:02:30 ] 特殊用途か設計ミスか勘違い
221 名前:デフォルトの名無しさん mailto:sage [2006/01/23(月) 22:48:39 ] >>217-220 まさに、その「設計ミス」(要は、バグ) で、 スレッド作りすぎてアプリケーションエラー 出しまくった俺が来ましたよ。 うちの環境だと、1600個位でおかしくなった。 ただスレッドを生成するのが、メーカー提供の COM の中なので、生成する時にどんなエラー が返ってきているかはよくわからん。
222 名前:デフォルトの名無しさん mailto:sage [2006/01/24(火) 14:21:13 ] なんじゃそりゃ(´・ω・`)
223 名前:デフォルトの名無しさん mailto:sage [2006/01/24(火) 23:34:23 ] >>196 例えば 1.CreateEvent の第2引数が FALSE(自動リセットオブジェクト)である 2.スレッドAが WaitForSingleObject(hEvent, INFINITE) している 3.スレッドBが SetEvent(hEvent) を呼び出す 4.スレッドAが待機状態から解放される 5.スレッドBが WaitForSingleObject(hEvent, 0) を呼び出す こういう場合、他のスレッドが ResetEvent しなくても 5.は WAIT_TIMEOUT を返すけど、CreateEvent の第2引数が TRUE なら WAIT_TIMEOUT を返すのは おかしいね。
224 名前:デフォルトの名無しさん mailto:sage [2006/01/25(水) 20:29:21 ] WAIT_OBJECT_TIMEOUT って書いてたことがばれて逃げてったやつに追い討ちかけんなよ。
225 名前:デフォルトの名無しさん mailto:sage [2006/01/27(金) 17:33:55 ] A.EXE と B.DLL があり、B.DLL が foo() という関数をエクスポートしており、 foo() は内部的に strtok 等の C ランタイム関数を呼ぶとする。 B.DLL 内部で _beginthread(ex) したスレッドの中で foo() を呼ぶのは当然問題 ないはずだけど、A.EXE が内部で CreateThread または _beginthread(ex) した スレッドの中で B.DLL の foo() 関数を呼び出した場合、メモリリークするの? B.DLL が DLL_THREAD_ATTACH/DETACH できちんとスレッドごとの初期化・後始末 をしていれば大丈夫そうな気がするんだけど、VC とか BC とかの C ランタイム ライブラリはこの辺どうなってるんだろう。
226 名前:デフォルトの名無しさん mailto:sage [2006/01/27(金) 18:21:34 ] CreateThreadで作ったスレッドはCランタイムライブラリを使ってはいけない。 スレッド内部でCランタイムライブラリを使いたい場合は、_beginthreadexを使おう。 _beginthreadはVBみたいなもんだと思おう。 詳しくはMSDNライブラリを参照のこと。 ttp://msdn.microsoft.com/library/ja/vclib/html/_crt__beginthread.2c_._beginthreadex.asp ランタイム ライブラリ リファレンス _beginthread、_beginthreadex ttp://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpdllpro/html/_win32_createthread.asp プラットフォーム SDK CreateThread ttp://support.microsoft.com/default.aspx?scid=kb;ja;104641 C ランタイム(CRT)関数と CreateThread ()を使用するの、説明
227 名前:デフォルトの名無しさん mailto:sage [2006/01/27(金) 20:30:26 ] >>225 むしろ逆。 B.DLL内部で_beginthread(ex)したスレッドからA.EXE中の関数bar()を呼ぶとリークする。 ただしA.EXEがCRTとスタティックリンクしていて実行環境がWindows Server 2003より前の場合。 ttp://codezine.jp/a/article.aspx?aid=235&p=2#col4 CRTはソース公開されてるから気になるなら読むといいよ。 Express Editionだと付いてるか知らんけど。
228 名前:225 mailto:sage [2006/01/27(金) 23:32:29 ] >>227 > B.DLL内部で_beginthread(ex)したスレッドからA.EXE中の関数bar()を呼ぶとリークする。 コールバック関数とかも、そのコールバック関数が自EXE で _beginthread(ex) したスレッドから呼ばれないなら C ランタイムを使えないことになりますね。 >>227 の質問を繰り返すことになりますが、A.EXE 内部で _beginthread(ex) した スレッドから B.DLL 中の関数 foo() を呼ぶのは大丈夫なんでしょうか。 DllMain の DLL_THREAD_ATTACH/DETACH はこのへんの問題を解決するための 機構だと思ってるので、きっと大丈夫なんだと自分に言い聞かせるようにし てるんですが…。
229 名前:225 mailto:sage [2006/01/27(金) 23:34:18 ] >>227 > CRTはソース公開されてるから気になるなら読むといいよ。 VC6 のソースを見る限りでは、DLL_THREAD_ATTACH/DETACH でスレッドごとの 初期化/後始末をしているようです。 CRT を使う DLL に関して、VC6 のソースを見た感じでは、その DLL が C ランタイムをスタティックリンクしている場合は _DllMainCRTStartup 内で DllMain を呼ぶ前に DisableThreadLibraryCalls を呼ばないようです。 MSVCRT.DLL を使用する場合は、ユーザー定義の DllMain がない場合のみ、 DisableThreadLibraryCalls を呼んでいるようです。DllMain があった場合、 DllMain 内部で DLL_THREAD_ATTACH/DETACH が必要になる可能性があるから DisableThreadLibraryCalls を呼ばないようにしてるのでしょう。おそらく。 だから、EXE 側で作成したスレッド内で、DLL 側の C ランタイム関数を使う 関数を呼び出しても、DLL_THREAD_DETACH で後始末が行われるのでメモリリーク は発生しないのではないかと思ってますが、それが明記されているドキュメント が見当たらないので気になっています。
230 名前:225 mailto:sage [2006/01/27(金) 23:36:13 ] EXE 側で作成したスレッド内で、DLL 側の関数(内部的に C ランタイム関数を 使うもの)を使えない(使うとメモリリークする)としたら、まともなマルチ スレッドアプリケーションなんて開発出来ない気もします。 せめて malloc/free/new/delete くらいは問題なく使えるようでないと…。 でも、 support.microsoft.com/default.aspx?scid=kb;ja;104641 を見ると malloc も駄目みたいですよね…。実際のところどうなんでしょ。
231 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 07:40:26 ] 実際のところってもなあ hackして怪我するのってあほらしくないか
232 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 10:30:25 ] >>230 Cランタイム関数はスレッドなんてのが出来るまえのシロモノだからね。 漏れの知る限りでは、 リンクしてるCランタイムライブラリが同じでマルチスレッド対応なら、 EXEとDLLで相互に呼び合いとかしても別段問題ない。 なぜなら、Cランタイムが使う領域は_beginthread*()でスレッド生成時に スレッドローカルに確保されて、そちらが使用されるから。 (→see AdvancedWindows) ただし、_*thread*()はランタイムライブラリに含まれる関数だから、 異なるライブラリを混在すると問題になる場合がある。 MS libcmtとMSVCRTの混在も危険。 (→see MSDNの/MDあたりのオプションのヘルプ)
233 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 10:43:44 ] >>230 それ英語版の方読めよ。機械翻訳で日本語として成立してない。 support.microsoft.com/?scid=kb%3Ben-us%3B104641&x=11&y=5 > スレッド内部でCランタイムライブラリを使いたい場合は、_beginthreadexを使おう。 で > calling malloc(), fopen(), _open(), strtok(), ctime(), or localtime() も問題なし。_endthreadex() が、CRT per-thread data-block を後始末してくれるから。
234 名前:225 mailto:sage [2006/01/28(土) 14:56:16 ] ちょっと試してみました。 B.DLL void foo(void) { char dummy[256]; strtok(dummy, ""); } A.EXE DWORD WINAPI ThreadProc(void *pvParam) { foo();//B.DLL 内の関数 return 0; } void test(void) { HANDLE hThread; DWORD dwThreadId; int i; for(i = 0; i < 10000; i++){ hThread = (HANDLE)CreateThread(NULL, 0, ThreadProc, 0, 0, &dwThreadId); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } }
235 名前:225 mailto:sage [2006/01/28(土) 14:57:27 ] >>234 の続き 1.A.EXE: BCB5 で作成、B.DLL: VC6 libcmt.lib で作成 2.A.EXE: BCB5 で作成、B.DLL: VC6 msvcrt.lib で作成 3.A.EXE: BCB5 で作成、B.DLL: BCB5 で作成 結果: 1:DllMain で DisableThreadLibraryCalls を呼ぶとメモリリークする (test を呼ぶ度にメモリ使用量が増える) DllMain で DisableThreadLibraryCalls を呼ばなければメモリリークしない (test を何回呼んでもメモリ使用量は変わらない) 2:DllMain で DisableThreadLibraryCalls を呼んでも呼ばなくてもメモリリークしない 3:DllMain で DisableThreadLibraryCalls を呼んでも呼ばなくてもメモリリークする ちなみに void foo(void) { char* dummy = (char*)malloc(128);// char *dummy = new char[128]; free(dummy);// delete[] dummy; } の場合、どの場合においてもメモリリークしない
236 名前:225 mailto:sage [2006/01/28(土) 14:59:56 ] >>235 の続き 結論: BCB5/VC6 で作成した B.DLL においては、C ランタイムルーチンのうち、少なくとも malloc/free/new/delete しか使わない分には、A.EXE で作成したスレッド内で B.DLL の関数を呼び出してもメモリリークしない。スレッドの作成に _beginthread(ex) を 使う必要もない。 VC6 で MSVCRT.DLL とリンクする B.DLL では、A.EXE で作成したスレッド内で B.DLL の関数(内部で C ランタイム関数を呼ぶもの)を呼び出してもメモリリークしない。 VC6 で libcmt.lib とスタティックリンクする B.DLL では、DllMain で DisableThreadLibraryCalls() を呼ばなければ、A.EXE で作成したスレッド内で B.DLL の関数(内部で C ランタイム関数を呼ぶもの)を呼び出してもメモリリーク しないが、DisableThreadLibraryCalls()を呼ぶと、B.DLL が内部で呼び出している C ランタイムルーチンによってはメモリリークする可能性がある。 他にも色んな組み合わせが考えられますが、とりあえず自分が知りたかった 「A.EXE で作成したスレッド内で B.DLL 内の関数を呼び出してもメモリリーク しないのか」は検証出来ました。この程度の実験で検証出来たと断言して良い のかはわかりませんが。 BCB5 の C ランタイムルーチンは DLL_THREAD_ATTACH/DETACH をきちんと処理して いないものと思われます。BCB5 で作った DLL はマルチスレッドアプリケーション からは使いにくいですね。 VC7 以降とか GCC とかではどうなんでしょうね。 検証の仕方が間違ってたらご指摘下さい。
237 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 15:25:22 ] >>236 率直に言えば無意味な検証。 というのは、メモリリークだけが問題ではないから。 仮にメモリリークしていなかったとしても、 複数のスレッドで同時に1つのワークエリアを参照していれば、 各スレッドがお互いに1つのワークエリアをぶっ壊しあう。 喪前さんのやり方では、そのパターンが検出できない。 むしろ、メモリリークしている方が複数のスレッドで異なるワークエリアを作成している、 つまり不完全ながらもマルチスレッド対応しているという見方もできる。 (実際どうかは知らん。メモリだけ確保して1つのワークを壊しまくってる可能性もある) つか、なんでCreateThread()で試してるんだ? 試すまでもなく駄目なの分かり切ってるだろ。 _beginthread*()ならまだわからんでもないが・・・。
238 名前:225 mailto:sage [2006/01/28(土) 18:02:37 ] > 複数のスレッドで同時に1つのワークエリアを参照していれば、 > 各スレッドがお互いに1つのワークエリアをぶっ壊しあう。 マルチスレッド対応のランタイムでは、そのような問題は起こらないことが 保証されているものだと思ってました。 _beginthread(ex) の説明を読む限り、メモリリーク問題以外については 何も記述されていません。 > つか、なんでCreateThread()で試してるんだ? 確認したかったのは、「A.EXE で作成したスレッド内で B.DLL 内の関数を 呼ぶことが出来るかどうか」だからです。 A.EXE は BCB5 で作成していて、B.DLL は VC6 で作成しています。 B.DLL 内の C ランタイムルーチンを使うのに、A.EXE の _beginthread(ex) を使っても無意味なのは初めからわかりきっています。 また、>>235 では書きませんでしたが、3.の場合、C ランタイムルーチン はスタティックリンクされてるので、やはり A.EXE の _beginthread(ex) と B.DLL の _beginthread(ex) は全く別物です。 > 試すまでもなく駄目なの分かり切ってるだろ。 メモリリークという点だけ見れば、駄目とは言い切れないという結果に なったと思うのですが。元々 DLL_THREAD_ATTACH/DETACH で解決し得る 問題だと思ってるので、この結果がおかしいとは思えません。
239 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 18:45:54 ] >>238 > マルチスレッド対応のランタイムでは、そのような問題は起こらないことが > 保証されているものだと思ってました。 思うのは勝手だけど、正しい使い方をしないと正しい挙動はしてくれないよ。 この場合、_beginthread*()を呼ばないと、「正しい挙動」はしてくれない。 なぜなら、Cランタイムをスレッドセーフにする肝心の処理を_beginthread*()がやるから。 ついでに言えば、問題はB.DLLだけの話ではなくて、A.EXEのランタイムに 何を使ってるか? というのも重要。にも関わらず、>>235 でその点に 一切触れていない点からも、喪前さんの理解が足りないことが伺える。
240 名前:225 mailto:sage [2006/01/28(土) 20:18:06 ] >>239 > なぜなら、Cランタイムをスレッドセーフにする肝心の処理を_beginthread*()がやるから。 _beginthread(ex) と _endthead がやるのは、スレッドごとに必要なメモリ の割り当てと解放を行うことですよね? _beginthread を使わなかったせいで、ランタイムルーチンを呼び出し時に そのスレッドではまだメモリが割り当てられてなかったなら、その場で動的に 割り当てれば問題ないでしょう。実際、動的に割り当ててると思うんだけど。 問題なのは、スレッドの終了を知ることが出来なくなるせいで、割り当てた メモリを解放する機会が得られなくなり、その結果としてメモリリークが発 生する、ということではないの? _beginthread(ex) を使わないことによって、排他処理的な問題が起こるとは どこにも書いてないですよね?起こらないとも書いてないけど。 排他処理的な問題が起こると明記されてるのは、シングルスレッド版の ランタイムを使った場合の方だけです。 マルチスレッド版の方では、メモリリークのことしか書いてないと思う んですけど。 > ついでに言えば、問題はB.DLLだけの話ではなくて、A.EXEのランタイムに > 何を使ってるか? というのも重要。にも関わらず、>>235 でその点に > 一切触れていない点からも、喪前さんの理解が足りないことが伺える。 A.EXE は BCB5 で作成、B.DLL は VC6 で作成と書いてます。 理解が足りないのは認めますが。 長文ばかりで申し訳ない。
241 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 20:54:27 ] とりあえず消えろ
242 名前:225 mailto:sage [2006/01/28(土) 21:09:14 ] >>241 真面目に質問してるつもりなんですが、そういうのが伝わらない あたりが 2ch のイヤなところですね。 どこかにこの件に関してきちんと解説したウェブサイトなり書籍 があればご紹介頂きたかったですがね。
243 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 21:19:39 ] >>242 そういうのにいちいち気にしていたら駄目だよw 2chの使い方からまず学んだほうが有効に使えるかも。 当然俺のレスにもレスは要らないぞw(あってもいいけど
244 名前:225 mailto:sage [2006/01/28(土) 21:40:13 ] >>243 やっぱりそうですか。(^^; >>235 の結果から、(この検証が正しければ)メモリリークに関しては 処理系依存ということになったわけだし、ドキュメント化されてるわけ でもないようだから、結局のところ結論なんて出ないんだろうな…。 「A.EXE で作成したスレッドから B.DLL の関数を呼び出すとメモリリークする」 のだとすると、Susie プラグインとか、自分ではメンテナンス出来ないプラグイン 方式の DLL を使うアプリをマルチスレッド化するのは非現実的ということになっ てしまうのか…。ほとんどの DLL は C ランタイムを使用してるだろうから。 一度作成したスレッドはアプリが終了するまで使い回すようにするしかないの だろうか…。なんか納得行かないな。
245 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 22:06:40 ] Susieプラグイン使う様なサイズのアプリなら、 スレッドプール使えば"about 70-80 bytes"のリークなんて気にする必要ないのでは? >>242 MSDNだろ。
246 名前:241 mailto:sage [2006/01/28(土) 22:09:50 ] マルチスレッドプログラミングをしたことのない房でも225のような真面目なやつを馬鹿にできるんだから 2chって憂さ晴らしに最適だよな。
247 名前:デフォルトの名無しさん mailto:sage [2006/01/28(土) 23:06:33 ] >>231
248 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 01:07:13 ] >>244 真面目におかしなことばっかり言ってるから相手したくなくなるんだよ。 依存するのは処理系自体ではなくライブラリだし、 アンドキュメントな実装に依存したコードを書くのは無謀。 漏れが言えることは、 「EXE・DLLの両方で同じライブラリ使ってれば、相互に呼び合いしても問題ない」 「泥沼に足突っ込みたくなければ推奨されてるやり方を使え」 それだけ。普通にMSVCRT使えばいい。 それ以上のこと知りたいなら、AdvancedWindowsなりMSDNなりCRTのソースなり 自分で読んで勉強してくれ。スレでいちいち書けるほど単純な話でもない。
249 名前:225 mailto:sage [2006/01/29(日) 04:20:43 ] >>248 > 「EXE・DLLの両方で同じライブラリ使ってれば、相互に呼び合いしても問題ない」 DLL は他人が作ってるので自分でいじれないし、EXE は GUI の 関係上 BCB しか使えないので。 > 「泥沼に足突っ込みたくなければ推奨されてるやり方を使え」 EXE で作成したスレッドから DLL の関数を呼ぶ場合の推奨されてる やり方とは?EXE/DLL ともに MSVCRT を使うことですか? > AdvancedWindowsなりMSDNなりCRTのソースなり自分で読んで勉強してくれ MSDN と CRT のソースは自分なりに熟読してみたつもりです。 CRT のソースから、>>235 の結果は予想通りでした。 でも、3.の結果は予想通りだけど納得行かない。 BCB5 の C ランタイムライブラリのバグと言うべきなんじゃないだろうか。 仕様で片付けていい問題ではないような…。 AdvancedWindows を読んでもう少し勉強してみます。
250 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 09:28:51 ] 最後のはBorlandのドキュメント読まないと仕方ないでしょ。 使ったことないから、どういう事になっているのか知らないし、 それで仕様通りの利用かどうかもわからない。 いずれにせよ、サードパーティのDLL内で、 CreateThread()を多発してない限り、別に大きな障壁になることじゃないよね。 スレッドを多発する場合、スレッドプール使うのは鉄則だから。
251 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 18:37:53 ] >>237 >>239 やなやつだなあ。 まじめに答えてる振り装ってるが不快なことこの上ない。
252 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 19:09:23 ] まあスレッドプログラミングなんてやってる香具師はそんな香具師ばっかりだから
253 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 19:30:17 ] だから日本はだめなんだよな
254 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 19:57:56 ] >>252 いっしょにすな!
255 名前:デフォルトの名無しさん mailto:sage [2006/01/29(日) 21:20:17 ] support.microsoft.com/?scid=kb%3Ben-us%3B104641&x=11&y=5 の"static"の使い方は違和感あるなあ。 "thread local"ってことだよな。実際は生存期間が"dynamic"だし。
256 名前:デフォルトの名無しさん [2006/01/30(月) 17:17:51 ] マルチスレッドでプログラムを作っているのですが、VisualC++6.0(SP6)でデバッグすると しばらくするとフリーズしてしまいます。 フリーズというのは、VC++と実行しているEXEがまったく応答しなくなり、 さらにOSの反応がほとんどなくなる感じです。 ほとんどというのは、Alt+Tabぐらいは効くのですが、タスクマネージャーも起動せず 他のアプリも、しばらく動くのですがじきに応答がなくなります。 デバッグではなく、ただEXEを実行した場合は普通です。 OSはWindowsXPHome SP2で、まあ標準的な環境だと思います。 1つ怪しいのといえば、NortonAntiVirusですが、これに関しては ほぼインストールしたてのWin2000SP4のマシンでやっても同じような現象が 起こったので、他のアプリが邪魔している、というわけでもなさそうです。 それなりに長いソースなので、同様の問題が発生する簡単なソースをコピペします。
257 名前:256 [2006/01/30(月) 17:18:38 ] #include <windows.h> #include <stdio.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); char* szClassNme = "aaa"; DWORD WINAPI thread_proc(LPVOID param) { int i; while(1) { i++; Sleep(10); } }
258 名前:256 [2006/01/30(月) 17:19:29 ] int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; WNDCLASS WClass; HWND hWnd; DWORD tid; if (!hPreInst) { WClass.style= CS_HREDRAW | CS_VREDRAW; WClass.lpfnWndProc= WndProc; WClass.cbClsExtra= 0; WClass.cbWndExtra= 0; WClass.hInstance= hInstance; WClass.hIcon= NULL; WClass.hCursor= LoadCursor(NULL, IDC_ARROW); WClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH); WClass.lpszMenuName= NULL; WClass.lpszClassName= szClassNme; if(!RegisterClass(&WClass)) return 0; } hWnd = CreateWindow(szClassNme, "aaa", WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 200, 200, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
259 名前:256 [2006/01/30(月) 17:24:07 ] while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } return 0; }
260 名前:256 [2006/01/30(月) 17:30:36 ] thread_procの、while(1)のところにブレークポイントを設定し F5を連打し何回かループさせると、いずれ固まります。 ひょっとしてプログラムに何か原因があるのでしょうか? デバッグがままならないとなると開発が非常に困難です。
261 名前:256 [2006/01/30(月) 20:19:40 ] WinXPで、ウィンドウズキー+Lで、ユーザーを切り替ることはできたので 別のユーザーからMSDEV.exeを強制終了すると、一応復帰できることが分かりました。 しかし、依然として非常に困っています。 もし以前こんな現象に見舞われたけど、こうして直したよ、とか ここをこうしたらいいんじゃないの?っていうのがありましたらぜひ教えていただきたいです。
262 名前:デフォルトの名無しさん mailto:sage [2006/01/30(月) 20:32:17 ] osの再インストールしても直らなかったという、ほろ苦い思い出があるよ。
263 名前:256 mailto:sage [2006/01/30(月) 21:32:25 ] >262 その後は結局どうなりました? ひょっとしてマルチスレッドのデバッグは、VC++6.0でできないっていうのが 「仕様」なんでしょうか?
264 名前:デフォルトの名無しさん mailto:sage [2006/01/30(月) 21:52:07 ] Windowsを2000にするか、VisualStudioをバージョンアップしませう
265 名前:256 mailto:sage [2006/01/30(月) 22:01:27 ] >264 Windows2000でもなりました。 VisualStudioをバージョンアップですか.... 高かったんですよね。
266 名前:デフォルトの名無しさん mailto:sage [2006/01/30(月) 22:26:40 ] >>256 私も Windows2000 から XP にアップグレードしてから似たような 現象が発生するようになりました。 VC++6.0 と BCB5 でそうなっていて、どちらもマルチスレッド アプリケーションでなくても発生します。 なんか Window メッセージの送受信の応答がシステム全体でとてつもなく 遅くなる感じですね。バックグラウンドで音楽とか流していても、音楽は 普通に流れますが、ウィンドウの切り替えとかがものすごく遅くなります。 完全なフリーズじゃないだけに、諦めて電源を落とそうにも、落とすタイ ミングに困ってしまうというか。 ttp://www.wg7.com/w2ktips/#CTFMON これと似たような症状なんですが、私は試していません。言語バーが 使えなくなるのも困るので。 結構頻繁に起こるので辛いのですが、起こらないときは起こらないので、 そういうものだと思って諦めています。
267 名前:225 mailto:sage [2006/01/30(月) 22:43:46 ] _beginthread(ex) の説明のところに、CreateThread だとメモリリークして しまう C ランタイム関数の一覧でも書いてあれば良いんですけどね。 ttp://support.microsoft.com/?scid=kb%3Ben-us%3B104641&x=11&y=5 には malloc とか fopen でもメモリリークするようなことが書かれてるけど、 実際に試してみると、VC6/BCB5 どちらの場合もメモリリークしてるようには 思えないです。 ここに書かれてないものでは、rand() を使うとメモリリークしますね。 今回の呼び出しの結果が前回の呼び出しに依存するようなタイプの関数は 全滅なんでしょうね。
268 名前:256 [2006/01/30(月) 22:55:37 ] >266 確かに今まで他のプログラムを組んでいるときにそういうことはありました。 しかし、今回はそれとはちょっと違うように思えるのです。 一度固まると、少なくとも20分ぐらいは待ってみたのですが復帰しませんでした。 しかも、ほぼ毎回起こります。 上のソースに何か問題点があるのでしょうか? ウィンドウメッセージに応じて処理をするスレッド(最初に起動されたときのもの) 別に他の計算をするスレッドを別に作っています。 競合が起こっているのかと思い、上のような簡単な簡単なソースを書いてみたのですが あれでも必ずといっていいほど起こります。 ちなみにWindowsMeでも起こりました。家のPC全滅です..
269 名前:266 mailto:sage [2006/01/31(火) 00:34:55 ] 最初は自分が書いたプログラムに原因があると思ってたのですが、 Web 上にある他人が書いたもののいくつかを自分の環境でコンパイル・実行 してもそうなるので、環境によるものだと思って諦めることにしました。 Windows2000 では問題なかったので、256 さんと私とでは状況が 少し異なりますね。マルチスレッドアプリケーションでなくても 発生しますし。お役に立てなくてすみません。
270 名前:デフォルトの名無しさん mailto:sage [2006/01/31(火) 01:33:38 ] オレもよくなる。ステップ実行しているとなんでもないところで固まってCtrl+Alt+Delをやって再起動とかやるが まったく動かず、次にAlt+Tabで悪あがき。選択した窓から順に固まる。 最後電源長押し、するとmsdev.exeを終了しています、かなんかがでて、msdev.exeが終了するとほかもサクサク終わる。 もちろんまったく終わらないでそのまま固まることもある。 DLLで提供される関数をステップオーバーしたときに出るとか、なんか最初はそんなことを思っていたけど そうでもないらしい。
271 名前:デフォルトの名無しさん mailto:sage [2006/01/31(火) 09:31:42 ] Windowsのスケジューラ糞馬鹿だから タスクマネージャでMSDEV.EXEのプライオリティ上げろ。
272 名前:256 mailto:sage [2006/01/31(火) 21:11:22 ] VisualStudio .NET 2003を入れてデバッグしてみたところ、簡単なものは ほとんど固まらなくなりましたが(とはいえ、ごくたまに固まります) 開発しているプログラムは依然として固まるようです。 いまいちすっきりしないのですが、あまりこの問題にかまっている時間的 余裕も無いのでデバッグ時のみシングルスレッドで動くようにして 場当たり的な解決をすることにしました。 幸運にもあまり修正せずにすむに済みました。 依然として自分のプログラムに問題があるのかという不安はのこりますが... 266さんをはじめ、皆様、様々な情報提供ありがとうございます。 よくあることのようなので、少し安心しました。(していいのか!?)
273 名前:デフォルトの名無しさん mailto:sage [2006/01/31(火) 21:27:49 ] >263 imeだか関係の問題だったはず。 ttp://ww1.enjoy.ne.jp/~turikiti/knowledge/program/oboegaki.htm の、マルチスレッドの注意点の項を参考にしてみては? 私は効果なかったんですが・・・
274 名前:デフォルトの名無しさん mailto:sage [2006/02/01(水) 01:56:10 ] 257のコードで何にも問題は出なかったぞ。 F5押しっぱなしでも固まるどころか快調そのもの。 Dual Pentium III 1GHz, NT4.0 VC++ 6.0+Sp5
275 名前:デフォルトの名無しさん mailto:sage [2006/02/03(金) 16:12:33 ] >>256 デバッグモードでなぜかおかしくなるというWin個体は確かにある。 どうしようもない。マシン変えろ
276 名前:sage [2006/02/04(土) 00:23:14 ] VB6.0でActiveX DLLを使用し、マルチスレッドを実現できるという噂を聞いたのですが 本当ですか? でもイメージが掴めない・・・ VBでActiveXコンポーネント「A」を呼び出し ↓ A作成→A何らかの処理 ↓ VBの処理←A処理終了 ↓ VB次の処理 って感じでマルチスレッドとは違う気がするんですが・・ もし本当であれば、どなたか参考になるサイトをご教授頂けませんでしょうか
277 名前:デフォルトの名無しさん [2006/02/04(土) 01:43:21 ] search.yahoo.co.jp/search?p=Visual+Basic+ActiveX+%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89&ei=UTF-8&fr=top&fl=0&x=wrt&meta=vc%3D
278 名前:デフォルトの名無しさん mailto:sage [2006/02/04(土) 08:38:15 ] >>276 DLLの中はC++で書けばなんでもやり放題なんじゃね? DLLの中でクリートスレッド
279 名前:デフォルトの名無しさん mailto:sage [2006/02/04(土) 09:02:03 ] >>278 クリートスレッドってなに?
280 名前:デフォルトの名無しさん mailto:sage [2006/02/04(土) 09:39:29 ] CreateとDeleteの合成語だろ スレッドを作ったら自分で閉じろってことだ
281 名前:デフォルトの名無しさん mailto:sage [2006/02/04(土) 12:14:10 ] >>276 ActiveX のコンポーネントとして作成した DLL/EXE が スレッドセーフだ、ってだけじゃね?
282 名前:デフォルトの名無しさん mailto:sage [2006/02/04(土) 12:20:51 ] 何をしたいのかしらんが COMのスレッドは楽しいぞ
283 名前:デフォルトの名無しさん mailto:sage [2006/02/06(月) 19:46:27 ] CreateThreadをクリートスレッドって読んだんだろ。 馬鹿みたいだが。
284 名前:デフォルトの名無しさん [2006/02/11(土) 07:40:21 ] もう二日も考え込んでるんですが解決しないんで質問です。(うう、マジで目と頭が痛い…。) 基本的に生産者消費者問題なんですが Aが物を作るとBに渡し、Bが物を作るとCに渡し、Cが物を作るとDに渡す、というように 複数の生産者/消費者のベルトコンベヤーでの流れ作業を想定しています。 で以下のように組んでみたんですが、 今度はB自身が消費したことをB自身に知らせなくてはならなくてこんがらがってきました。 public class Main { public static void main(String args[]) { ConveyerBelt stationAB = new ConveyerBelt(); ConveyerBelt stationBC = new ConveyerBelt(); ConveyerBelt stationCD = new ConveyerBelt(); Worker producerA = new Worker(stationAB); Widget consumerB = new Widget(stationAB); Worker producerB = new Worker(stationBC); Widget consumerC = new Widget(stationBC); Worker producerC = new Worker(stationCD); Widget consumerD = new Widget(stationCD); producerA.start(); consumerB.start(); producerB.start(); consumerC.start(); producerC.start(); consumerD.start(); } } ConveyerBelt()バッファーが三つというのは正しいと思うんですけど スレッドはABCDの四つだけ作ればいいんでしょうか?どなたかご教授下さい。
285 名前:284 [2006/02/11(土) 07:43:18 ] ちなみにセマフォは「なし」の方向でお願いします。
286 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 07:47:19 ] 日本語で質問してください
287 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 08:44:23 ] >>284 Chain Of Responsibility パターンはもう検討済みなの?
288 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 10:21:28 ] >>284 4つじゃないとダメなわけもないし、好きに作ればいい
289 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 12:09:10 ] 各々理由を書いてね。 > 今度はB自身が消費したことをB自身に知らせなくては > ならなくて > ちなみにセマフォは「なし」の方向でお願いします。
290 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 18:57:50 ] >>289 正確厨、規格厨、口先厨の予感。現状提示されている情報から 回答が思いつかなければ、その問題に対する類似性や経験則 など思い当たるところが無いっつーことだろ。 全部の情報が分からないとコミュニケーションできないような 応用力無しやつは黙ってろ
291 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 19:56:02 ] >>9 Double Checked Lockingに追加 Scott Meyers & Andrei Alexandrescu "C++ and The Perils of Double-Checked Locking (II)" erdani.org/publications/DDJ_Jul_Aug_2004_revised.pdf 付録に"volatile: Brief History"あり。 Douglas C. Schmidt & Tim Harrison "Double-Checked Locking An Optimization Pattern for Efficiently Initializing and Accessing Thread-safe Objects" www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf
292 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 21:48:09 ] >>290 エスパー以外は黙れと。
293 名前:291 mailto:sage [2006/02/11(土) 22:33:21 ] せっかく流れ切ったのに…
294 名前:デフォルトの名無しさん mailto:sage [2006/02/11(土) 22:58:43 ] >>290 やんわりと、「設計がおかしいんじゃないか?」と言われてるんだよ。 まあ、もうまともな回答は期待できないだろうからどうでもいい話だが。
295 名前:284 [2006/02/12(日) 01:45:30 ] ご迷惑をお掛けしております。m(__)m >>287 そんな概念があったんですね。というくらいなので検討済みではないです。 検索してみていくつかサイトを見つけたのでもう少し読んでみます。 分からなければまた質問します。それと if (Thread.currentThread() == "Thread[Thread-0,5,main]") System.out.println("I am the Worker A."); のようなチェックを入れたいんですが、そんな比較はできないみたいです。 左辺値はどんな感じにすればいいんでしょうか? これができれば、一つ一つ鎖をつなげていける気がするんですが。 >>288 逆を言うと「4つでもできる」ということですか? >>289 現状を話しますと Aから渡された物をB自身が処理(消費)してもないのに (いや、時にはAから物を渡されてもないのに) Bは勝手に生産を始めてしまいます。 ですから現在はA-B間、B-C間、C-D間のみで同期がされてます。 それと、やっぱりセマフォアは「あり」でもいいです。
296 名前:デフォルトの名無しさん [2006/02/12(日) 05:05:21 ] ここでは綺麗でも汚くても叩かれますYOW