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/
152 名前:デフォルトの名無しさん mailto:sage [2005/12/19(月) 21:48:15 ] そもそもハングするのか? ハングはしないだろ
153 名前:145 mailto:sage [2005/12/20(火) 01:28:57 ] いろいろ調べてましたが IO絡みの関数は基本的にスレッドセーフに作られてるから ってのが答えみたいです お騒がせしました >>149 それは違います。たとえfcloseをコメントアウトしてもハングしません >>152 ハングはしないようですね このページに「大抵ハングしてしまいます」と書かれていて気になったのです www.kumei.ne.jp/c_lang/intro2/no_106.htm まあこのページに限らずネット上でマルチスレッドを初心者向けに教えているサイトでは 大抵同じような書かれ方がされてるので、 もしかすると私の検証が不十分なのかもしれませんが・・・
154 名前:デフォルトの名無しさん mailto:sage [2005/12/20(火) 04:36:05 ] 同時に書き込んで壊れなくても 後からの書き込みで前の書き込みは上書きされて消える訳だが
155 名前:デフォルトの名無しさん mailto:sage [2005/12/24(土) 14:28:30 ] >>153 ランタイムライブラリがスレッドセーフで無い場合はハングするかもしれないけど、 VS2005からシングルスレッドのランタイムは無くなっているなあ。
156 名前:デフォルトの名無しさん mailto:sage [2005/12/24(土) 14:44:54 ] 「ハングする」なんて言い方は止めて、 「動作が未定義」くらいにしてくれないか。 本当にハングアップするかどうかを問題にしているんじゃないだろ?
157 名前:デフォルトの名無しさん [2005/12/25(日) 13:24:46 ] >>156 このマニアめが。
158 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 13:38:00 ] /MT ってやってればたいがい大丈夫だろうけど、スレッドセーフでない関数で gethostbynameとかが未定の動作されるとかなり困る、 無理矢理排他同期とって使ってるけどなんかかっこ悪い。
159 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 13:45:27 ] winsockのgethostbynameはスレッドセーフじゃなかったっけ?
160 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 13:49:25 ] /MTってことはWindows? getaddrinfoはMT-Safeでしょ。 msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/getaddrinfo_2.asp には明記してないけど、gai_strerrorは違うから〜って書いているくらいだから。
161 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 13:54:49 ] 明記してあるな。 >Remarks >The gethostbyname function returns a pointer to a hostent structure-a structure allocated by >Windows Sockets. The hostent structure contains the results of a successful search for the >host specified in the name parameter. >The application must never attempt to modify this structure or to free any of its components. >Furthermore, only one copy of this structure is allocated per thread, so the application should ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > copy any information it needs before issuing any other Windows Sockets function calls.
162 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 13:57:38 ] struct hostent *host; host = gethostbyname(argv[1]); ってな形だし、どうみてもスレッドセーフでないと思ってた。 スレッド固有メモリなんてものでも使ってるのかな。
163 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 14:14:38 ] >>161 それだけでMT-Safeだとは限らない。
164 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 14:50:26 ] getaddrinfo ってのがあるんだ、 参考にしてた本が古っかったので知らなんだ。 該当箇所を書きかえねば orz
165 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 15:28:14 ] 2ちゃんで書き込みするときの文字2048制限解除方法誰か教えてください。
166 名前:デフォルトの名無しさん mailto:age [2005/12/25(日) 15:29:18 ] 制限解除して書き込んでる人が増えてるんですが
167 名前:デフォルトの名無しさん mailto:sage [2005/12/25(日) 15:38:13 ] >>164 古いWindowsではありませんのでその辺は配慮を。
168 名前:デフォルトの名無しさん mailto:sage [2005/12/26(月) 03:11:55 ] 「スレッドできる」と「スレッドでファイル操作しても問題ない」は同義じゃないよなあ。 単一リソース操作は対策しないと普通は競合するよ。
169 名前:デフォルトの名無しさん mailto:sage [2005/12/26(月) 19:09:27 ] マルチスレッドなサーバプログラムを作ってみようかと思ってます クライアント数が少ない場合1クライアントに1スレッドを割り当てればいいかなと思いますが クライアント数が多い場合はどういった方法が良いんでしょうか? 1スレッドあたりのクライアント数を決めてスレッドごとにselect()するとか 親スレッドでselect()して処理を別スレッドに任せるとか一応考えてはみていますが どういった方法がスタンダードなんですかね?
170 名前:デフォルトの名無しさん mailto:sage [2005/12/26(月) 20:42:42 ] ジョブキュー
171 名前:デフォルトの名無しさん mailto:sage [2005/12/26(月) 22:37:27 ] +スレッドプール
172 名前:デフォルトの名無しさん mailto:sage [2005/12/26(月) 23:38:08 ] 裏技としてApache 勉強にはならんな・・・
173 名前:デフォルトの名無しさん mailto:sage [2005/12/27(火) 13:56:11 ] apacheって何言ってんの? ネットワークプログラミング相談室にも沸いたバカだろか。
174 名前:デフォルトの名無しさん mailto:sage [2005/12/28(水) 15:39:12 ] なぜそこで、あと半歩踏み込んで「apache馬鹿よね〜」とか言えないよねぇ
175 名前:デフォルトの名無しさん mailto:sage [2005/12/28(水) 16:51:48 ] おバカSunよね〜
176 名前:デフォルトの名無しさん mailto:sage [2006/01/02(月) 08:35:56 ] くだらない質問ですみませんが TCPで同じディスクリプタにread()するスレッドとwrite()するスレッドを分けたとき 全二重だから同時にread()とwrite()を実行しても問題ありませんよね? あと片方が同期無しでclose()するのって問題ありますかね
177 名前:デフォルトの名無しさん mailto:sage [2006/01/02(月) 08:40:05 ] 同時にread/writeしても問題なし。 HTTPサーバのようなものを作ってるなら相手が一方的にclosesocketしたくらいでおかしくなっては困る。
178 名前:デフォルトの名無しさん mailto:sage [2006/01/02(月) 12:25:53 ] Solaris2.xではデッドロックしてたなあ(遠い目)
179 名前:デフォルトの名無しさん mailto:sage [2006/01/03(火) 03:50:46 ] x86 とかで int の値を書き込むスレッド(A)と読み込むスレッド(B)がある場合, 更新途中の値が(つまり 32bit 中の 16 bit が新しい値で残りが古いままとか) B に見えてしまうということはありうるでしょうか? # long とかだとまずいですよね.
180 名前:デフォルトの名無しさん mailto:sage [2006/01/03(火) 04:40:29 ] >>179 前スレで延々やってたと思う そこが本題でなければ、排他で済ませて先行った方がいいと思うヨ
181 名前:デフォルトの名無しさん mailto:sage [2006/01/03(火) 04:56:02 ] >>180 レスありがとうございます.前スレの読み方がよく分からないので憶測になっ てしまいますが,前スレの議論では結局「あり得る」という結論に至ったとの 理解で良いでしょうか? 参考になりそうな資料へのポインタを教えて頂けるとうれしいです. > そこが本題でなければ、排他で済ませて先行った方がいいと思うヨ 性能的な面から可能な限り B に対する排他処理は避けたいと考えています.
182 名前:デフォルトの名無しさん mailto:sage [2006/01/04(水) 15:07:19 ] >>181 OSに用意されている、Atomicな書き換えAPIを利用すれば宜しかろう。 32ビットバスでアライメントも合っていれば素直にAtomicに書き換わると思うが。
183 名前:デフォルトの名無しさん mailto:sage [2006/01/04(水) 16:15:06 ] レスありがとうございます。調べてみます.
184 名前:デフォルトの名無しさん [2006/01/13(金) 02:07:27 ] マルチスレッドプログラミングで注意することを列挙してくれ。
185 名前:デフォルトの名無しさん mailto:sage [2006/01/13(金) 02:19:22 ] ひとつ!急いで口で吸え!
186 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 14:53:41 ] ふたつ! 不埓な悪行三昧!
187 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 16:18:23 ] みっつ! 想定の範囲内です。
188 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 16:55:53 ] よっつ、読んでも書いちゃダメ
189 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 16:56:28 ] いつつ、いつも心に排他処理
190 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 16:59:48 ] むっつ、無理せずmutex
191 名前:デフォルトの名無しさん mailto:sage [2006/01/18(水) 17:21:48 ] ななつ、仲良くSemaphoeで共有
192 名前:>>46 mailto:sage [2006/01/18(水) 23:32:09 ] やっつ、やっぱりここでも排他処理
193 名前:デフォルトの名無しさん mailto:sage [2006/01/19(木) 00:43:25 ] ここのつ!心を鬼にして排他処理
194 名前:デフォルトの名無しさん mailto:sage [2006/01/19(木) 01:03:03 ] 糞スレ立てんな
195 名前:デフォルトの名無しさん mailto:sage [2006/01/19(木) 01:39:58 ] とう、でとうとう割り込まれた。 排他だけじゃなく、割り込み禁止も忘れないでね☆
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 ] まあスレッドプログラミングなんてやってる香具師はそんな香具師ばっかりだから