マルチスレッドプログラミング相談室 その4
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2005/11/03(木) 11:23:05OS・言語・環境は問わないが、それゆえ明記すべし。
その1 http://pc3.2ch.net/test/read.cgi/tech/997345868/
その2 http://pc5.2ch.net/test/read.cgi/tech/1037636153/
その3 http://pc8.2ch.net/test/read.cgi/tech/1098268137/
0153145
2005/12/20(火) 01:28:57IO絡みの関数は基本的にスレッドセーフに作られてるから
ってのが答えみたいです
お騒がせしました
>>149
それは違います。たとえfcloseをコメントアウトしてもハングしません
>>152
ハングはしないようですね
このページに「大抵ハングしてしまいます」と書かれていて気になったのです
http://www.kumei.ne.jp/c_lang/intro2/no_106.htm
まあこのページに限らずネット上でマルチスレッドを初心者向けに教えているサイトでは
大抵同じような書かれ方がされてるので、
もしかすると私の検証が不十分なのかもしれませんが・・・
0154デフォルトの名無しさん
2005/12/20(火) 04:36:05後からの書き込みで前の書き込みは上書きされて消える訳だが
0155デフォルトの名無しさん
2005/12/24(土) 14:28:30ランタイムライブラリがスレッドセーフで無い場合はハングするかもしれないけど、
VS2005からシングルスレッドのランタイムは無くなっているなあ。
0156デフォルトの名無しさん
2005/12/24(土) 14:44:54「動作が未定義」くらいにしてくれないか。
本当にハングアップするかどうかを問題にしているんじゃないだろ?
0157デフォルトの名無しさん
2005/12/25(日) 13:24:46このマニアめが。
0158デフォルトの名無しさん
2005/12/25(日) 13:38:00gethostbynameとかが未定の動作されるとかなり困る、
無理矢理排他同期とって使ってるけどなんかかっこ悪い。
0159デフォルトの名無しさん
2005/12/25(日) 13:45:270160デフォルトの名無しさん
2005/12/25(日) 13:49:25getaddrinfoはMT-Safeでしょ。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/getaddrinfo_2.asp
には明記してないけど、gai_strerrorは違うから〜って書いているくらいだから。
0161デフォルトの名無しさん
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.
0162デフォルトの名無しさん
2005/12/25(日) 13:57:38host = gethostbyname(argv[1]);
ってな形だし、どうみてもスレッドセーフでないと思ってた。
スレッド固有メモリなんてものでも使ってるのかな。
0163デフォルトの名無しさん
2005/12/25(日) 14:14:38それだけでMT-Safeだとは限らない。
0164デフォルトの名無しさん
2005/12/25(日) 14:50:26参考にしてた本が古っかったので知らなんだ。
該当箇所を書きかえねば orz
0165デフォルトの名無しさん
2005/12/25(日) 15:28:140166デフォルトの名無しさん
2005/12/25(日) 15:29:180167デフォルトの名無しさん
2005/12/25(日) 15:38:13古いWindowsではありませんのでその辺は配慮を。
0168デフォルトの名無しさん
2005/12/26(月) 03:11:55単一リソース操作は対策しないと普通は競合するよ。
0169デフォルトの名無しさん
2005/12/26(月) 19:09:27クライアント数が少ない場合1クライアントに1スレッドを割り当てればいいかなと思いますが
クライアント数が多い場合はどういった方法が良いんでしょうか?
1スレッドあたりのクライアント数を決めてスレッドごとにselect()するとか
親スレッドでselect()して処理を別スレッドに任せるとか一応考えてはみていますが
どういった方法がスタンダードなんですかね?
0170デフォルトの名無しさん
2005/12/26(月) 20:42:420171デフォルトの名無しさん
2005/12/26(月) 22:37:270172デフォルトの名無しさん
2005/12/26(月) 23:38:08勉強にはならんな・・・
0173デフォルトの名無しさん
2005/12/27(火) 13:56:11ネットワークプログラミング相談室にも沸いたバカだろか。
0174デフォルトの名無しさん
2005/12/28(水) 15:39:120175デフォルトの名無しさん
2005/12/28(水) 16:51:480176デフォルトの名無しさん
2006/01/02(月) 08:35:56TCPで同じディスクリプタにread()するスレッドとwrite()するスレッドを分けたとき
全二重だから同時にread()とwrite()を実行しても問題ありませんよね?
あと片方が同期無しでclose()するのって問題ありますかね
0177デフォルトの名無しさん
2006/01/02(月) 08:40:05HTTPサーバのようなものを作ってるなら相手が一方的にclosesocketしたくらいでおかしくなっては困る。
0178デフォルトの名無しさん
2006/01/02(月) 12:25:530179デフォルトの名無しさん
2006/01/03(火) 03:50:46更新途中の値が(つまり 32bit 中の 16 bit が新しい値で残りが古いままとか)
B に見えてしまうということはありうるでしょうか?
# long とかだとまずいですよね.
0180デフォルトの名無しさん
2006/01/03(火) 04:40:29前スレで延々やってたと思う
そこが本題でなければ、排他で済ませて先行った方がいいと思うヨ
0181デフォルトの名無しさん
2006/01/03(火) 04:56:02レスありがとうございます.前スレの読み方がよく分からないので憶測になっ
てしまいますが,前スレの議論では結局「あり得る」という結論に至ったとの
理解で良いでしょうか?
参考になりそうな資料へのポインタを教えて頂けるとうれしいです.
> そこが本題でなければ、排他で済ませて先行った方がいいと思うヨ
性能的な面から可能な限り B に対する排他処理は避けたいと考えています.
0182デフォルトの名無しさん
2006/01/04(水) 15:07:19OSに用意されている、Atomicな書き換えAPIを利用すれば宜しかろう。
32ビットバスでアライメントも合っていれば素直にAtomicに書き換わると思うが。
0183デフォルトの名無しさん
2006/01/04(水) 16:15:060184デフォルトの名無しさん
2006/01/13(金) 02:07:270185デフォルトの名無しさん
2006/01/13(金) 02:19:220186デフォルトの名無しさん
2006/01/18(水) 14:53:410187デフォルトの名無しさん
2006/01/18(水) 16:18:230188デフォルトの名無しさん
2006/01/18(水) 16:55:530189デフォルトの名無しさん
2006/01/18(水) 16:56:280190デフォルトの名無しさん
2006/01/18(水) 16:59:480191デフォルトの名無しさん
2006/01/18(水) 17:21:480192>>46
2006/01/18(水) 23:32:090193デフォルトの名無しさん
2006/01/19(木) 00:43:250194デフォルトの名無しさん
2006/01/19(木) 01:03:030195デフォルトの名無しさん
2006/01/19(木) 01:39:58排他だけじゃなく、割り込み禁止も忘れないでね☆
0196デフォルトの名無しさん
2006/01/21(土) 01:53:34SetEvent(hEvent);←TRUEがかえる
でも、その次に
WaitForSingleObject(hEvent, 0)とやってもWAIT_OBJECT_TIMEOUTがかえる。
こういうことがおきているのですがどのようなことが考えられますか?
0197デフォルトの名無しさん
2006/01/21(土) 07:15:10SetEventは成功したけど、イベントオブジェクトがシグナル状態になる前にWaitForSingleObjectがタイムアウトした。
0199196
2006/01/21(土) 14:20:25SetEventってシグナル状態にした後で戻るわけではないのですか?
>>198
ソースを見る限りほかのスレッドが触ることはなさそうなのですが確信持てないです。
SetEventとWaitForSingleObjectの間で他のスレッドにスイッチしなければそういうことはおきないですよね?
であれば確認のためにはスレッドのスイッチをSetEventとWaitForの間で抑制してあげればいいですよね。
なにか、任意のコードブロックではスレッドスイッチを禁止する方法はないでしょうか
0200デフォルトの名無しさん
2006/01/21(土) 14:26:18単に待てば委員で内科医?
0201デフォルトの名無しさん
2006/01/21(土) 14:42:020202デフォルトの名無しさん
2006/01/21(土) 15:04:56>>196の事象が事実であるなら、そういうものだと思って使うべき。
嫌なら別の手段を用いるべき。
0203196
2006/01/21(土) 15:47:24SetEventしてそれが本当にシグナルになったかを見るためにWaifFor・・したのですが、
それがなぜかシグナルになっていないのです。
>>201
検証ありがとうございます。>>196のままのコードだとそうなると思いますが、実際にはほかのスレッドもいるので
何が起きているかはよくわかっていません。(デバッガでステップ実行したりデバッグライトを入れるだけで動きが変わるため)
とりあえず、月曜にほかのスレッドがResetしていないか確認したいと思います
あとSetEventって非同期に動いたりしませんよね?
SetEvent(hEvent);
ここで誰かがResetEventしない限り下はTRUEにならないですよね?
if(WaitForSingleObject(hEvent,0)==WAIT_OBJECT_TIMEOUT)
{
}
0204デフォルトの名無しさん
2006/01/21(土) 17:01:11だから、WaitForSingleObject(hEvent, INFINITE)してみたら?
0205デフォルトの名無しさん
2006/01/21(土) 21:15:12成功:WAIT_OBJECT_0 or WAIT_TIMEOUT or WAIT_ABANDONED
失敗:WAIT_FAILED
のいずれかが、WaitForSingleObject()の戻り値なんだが・・・
とりあえず、該当部分のコードを晒せ、晒したくなかったらコピペも満足にできない房は二度とくんな。
0206>>46
2006/01/21(土) 23:02:03> ソースを見る限りほかのスレッドが触ることはなさそ
> うなのですが確信持てないです。
はぁ? 悪いけど、変数がどっからアクセスされるか自信
が持てないなんて言う奴にはマルチスレッドプログラムは
無理だよ。あきらめたら?
>>203 で、デバッガとか言ってるが君がやることは、デ
バッガでプログラムを追っかけることではなく hEvent
で全ソースに対して findstr することだと思う。
(そこらじゅうで hEvent 使ってるなら、問題のところ
の変数名を変えるべき。)
>>201
うちでも、CreateEvent() 〜 SetEvent() 〜
WaitForSingleObject() 〜 CloseHandle() を
10,000,000 回実行したが、WAIT_OBJECT_0 しか
返らないよ。
>>202
その考え方はおかしいだろ。
>>196 みたいな動きをするイベントなんて使い物にな
らないと思う。
0207デフォルトの名無しさん
2006/01/22(日) 08:57:50>>>196 みたいな動きをするイベントなんて使い物にな
>らないと思う。
eventは許可するまで待たせておくことが目的の物だから、setは少しくらい遅れても良いと思う。
acquireI->releaseする同期モノのreleaseも同じ。
0208>>46
2006/01/22(日) 10:13:10少しってどれぐらい?
1秒なの? 1ms なの? 1μs なの?
他のスレッドに対して set の伝播が遅れるのは問題ない
けど、自スレッドに対して SetEvent() してからイベン
トがセットされるまでの間に「隙間」があるのは問題。
例えば、
SetEvent(hEvent); // hEvent は、ワーカースレッドか処理終了でセットする。
StartWorkerThread(); // 処理開始指示。
while(WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT){ // 終了したか?
// 終了してないなら、他のことしてようっと。
}
(こんなプログラムは組むなと言う意見はまた別の機会に。)
と言うプログラムがうまく動かない。
動かないだけなら、まだしも下手するとうまく動いたり動
かなくなったりすると言う最悪パターンになる。
マルチスレッドプログラムやるなら「隙間」をもっと意識
できないとはまるよ。
0209デフォルトの名無しさん
2006/01/22(日) 12:18:00「こんなプログラムは組むな」
0210デフォルトの名無しさん
2006/01/22(日) 12:45:43>トがセットされるまでの間に「隙間」があるのは問題。
いやだから、その隙間は無いんだって。
というか、先頭のSetEventはResetEventの間違いだよな、な。
0211デフォルトの名無しさん
2006/01/22(日) 16:13:56下のスレでマルチコアについて侃侃諤諤の論争してるんですけど、
みなさんはこれからのマルチコア時代についてどう捉えていますか?
Intelの次世代CPUについて語ろう 21
http://pc7.2ch.net/test/read.cgi/jisaku/1136822334/
0212デフォルトの名無しさん
2006/01/22(日) 17:12:45次にタスクスイッチが起こったときにsetしてくれればいい程度に思って使ってるね、私は。
>while(WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT){ // 終了したか?
普通スレッド終了の検知はスレッドのハンドルをWaitForSingleObjectの引数にする。
わざわざeventなんて作らない。
スレッドをプールするなんて言い訳は聞かない。
>>211
面倒なことはOSに任せて今まで通りにやる。
0213>>46
2006/01/22(日) 20:04:17すまん、勘違いだ。
セット側はさすがにちょっと考えにくいな。
(まあ、リセット側も無理矢理だが。)
ただ、セット側とリセット側で挙動が違うのはちょっと気
持ち悪い。
>>211
マルチコアって言ったって、マルチプロセサの一形態だろ。
別に何か変えないといけないのか?
専用のチューニングが必要になったらそのとき勉強するよ。
>>212
> 普通スレッド終了の検知はスレッドのハンドルを
> WaitForSingleObjectの引数にする。
スレッドの終了 ≠ 処理の終了
誰も、スレッドの終了の検知方法なんて聞いてないぞ。
最近知ったので、知ったかしたくなったのか?
0214デフォルトの名無しさん
2006/01/22(日) 20:06:09さーしったかしったかたーこうりんだー
みぎあしくんひだりあしくん
0215デフォルトの名無しさん
2006/01/22(日) 20:17:49気が済んだか?
すっきりしたら、違うスレに行ってくれよな。
0216デフォルトの名無しさん
2006/01/22(日) 20:27:26>スレッドの終了 ≠ 処理の終了
そういうことを言いたかったのか。
0217デフォルトの名無しさん
2006/01/22(日) 21:08:07_beginthreadexを使おうと思っていますが、
1プロセスあたりに生成できるスレッド数って
決まっているのでしょうか?
MSDNのCreateThreadのヘルプには、
2028との数字がありますが・・・
0218デフォルトの名無しさん
2006/01/23(月) 00:53:270219デフォルトの名無しさん
2006/01/23(月) 00:57:580220デフォルトの名無しさん
2006/01/23(月) 22:02:300221デフォルトの名無しさん
2006/01/23(月) 22:48:39まさに、その「設計ミス」(要は、バグ) で、
スレッド作りすぎてアプリケーションエラー
出しまくった俺が来ましたよ。
うちの環境だと、1600個位でおかしくなった。
ただスレッドを生成するのが、メーカー提供の
COM の中なので、生成する時にどんなエラー
が返ってきているかはよくわからん。
0222デフォルトの名無しさん
2006/01/24(火) 14:21:130223デフォルトの名無しさん
2006/01/24(火) 23:34:23例えば
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 を返すのは
おかしいね。
0224デフォルトの名無しさん
2006/01/25(水) 20:29:21って書いてたことがばれて逃げてったやつに追い討ちかけんなよ。
0225デフォルトの名無しさん
2006/01/27(金) 17:33:55foo() は内部的に strtok 等の C ランタイム関数を呼ぶとする。
B.DLL 内部で _beginthread(ex) したスレッドの中で foo() を呼ぶのは当然問題
ないはずだけど、A.EXE が内部で CreateThread または _beginthread(ex) した
スレッドの中で B.DLL の foo() 関数を呼び出した場合、メモリリークするの?
B.DLL が DLL_THREAD_ATTACH/DETACH できちんとスレッドごとの初期化・後始末
をしていれば大丈夫そうな気がするんだけど、VC とか BC とかの C ランタイム
ライブラリはこの辺どうなってるんだろう。
0226デフォルトの名無しさん
2006/01/27(金) 18:21:34スレッド内部で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 ()を使用するの、説明
0227デフォルトの名無しさん
2006/01/27(金) 20:30:26むしろ逆。
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だと付いてるか知らんけど。
0228225
2006/01/27(金) 23:32:29> B.DLL内部で_beginthread(ex)したスレッドからA.EXE中の関数bar()を呼ぶとリークする。
コールバック関数とかも、そのコールバック関数が自EXE で _beginthread(ex)
したスレッドから呼ばれないなら C ランタイムを使えないことになりますね。
>>227 の質問を繰り返すことになりますが、A.EXE 内部で _beginthread(ex) した
スレッドから B.DLL 中の関数 foo() を呼ぶのは大丈夫なんでしょうか。
DllMain の DLL_THREAD_ATTACH/DETACH はこのへんの問題を解決するための
機構だと思ってるので、きっと大丈夫なんだと自分に言い聞かせるようにし
てるんですが…。
0229225
2006/01/27(金) 23:34:18> 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 で後始末が行われるのでメモリリーク
は発生しないのではないかと思ってますが、それが明記されているドキュメント
が見当たらないので気になっています。
0230225
2006/01/27(金) 23:36:13使うもの)を使えない(使うとメモリリークする)としたら、まともなマルチ
スレッドアプリケーションなんて開発出来ない気もします。
せめて malloc/free/new/delete くらいは問題なく使えるようでないと…。
でも、
http://support.microsoft.com/default.aspx?scid=kb;ja;104641
を見ると malloc も駄目みたいですよね…。実際のところどうなんでしょ。
0231デフォルトの名無しさん
2006/01/28(土) 07:40:26hackして怪我するのってあほらしくないか
0232デフォルトの名無しさん
2006/01/28(土) 10:30:25Cランタイム関数はスレッドなんてのが出来るまえのシロモノだからね。
漏れの知る限りでは、
リンクしてるCランタイムライブラリが同じでマルチスレッド対応なら、
EXEとDLLで相互に呼び合いとかしても別段問題ない。
なぜなら、Cランタイムが使う領域は_beginthread*()でスレッド生成時に
スレッドローカルに確保されて、そちらが使用されるから。
(→see AdvancedWindows)
ただし、_*thread*()はランタイムライブラリに含まれる関数だから、
異なるライブラリを混在すると問題になる場合がある。
MS libcmtとMSVCRTの混在も危険。
(→see MSDNの/MDあたりのオプションのヘルプ)
0233デフォルトの名無しさん
2006/01/28(土) 10:43:44それ英語版の方読めよ。機械翻訳で日本語として成立してない。
http://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 を後始末してくれるから。
0234225
2006/01/28(土) 14:56:16B.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);
}
}
0235225
2006/01/28(土) 14:57:271.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;
}
の場合、どの場合においてもメモリリークしない
0236225
2006/01/28(土) 14:59:56結論:
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 とかではどうなんでしょうね。
検証の仕方が間違ってたらご指摘下さい。
0237デフォルトの名無しさん
2006/01/28(土) 15:25:22率直に言えば無意味な検証。
というのは、メモリリークだけが問題ではないから。
仮にメモリリークしていなかったとしても、
複数のスレッドで同時に1つのワークエリアを参照していれば、
各スレッドがお互いに1つのワークエリアをぶっ壊しあう。
喪前さんのやり方では、そのパターンが検出できない。
むしろ、メモリリークしている方が複数のスレッドで異なるワークエリアを作成している、
つまり不完全ながらもマルチスレッド対応しているという見方もできる。
(実際どうかは知らん。メモリだけ確保して1つのワークを壊しまくってる可能性もある)
つか、なんでCreateThread()で試してるんだ?
試すまでもなく駄目なの分かり切ってるだろ。
_beginthread*()ならまだわからんでもないが・・・。
0238225
2006/01/28(土) 18:02:37> 各スレッドがお互いに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 で解決し得る
問題だと思ってるので、この結果がおかしいとは思えません。
0239デフォルトの名無しさん
2006/01/28(土) 18:45:54> マルチスレッド対応のランタイムでは、そのような問題は起こらないことが
> 保証されているものだと思ってました。
思うのは勝手だけど、正しい使い方をしないと正しい挙動はしてくれないよ。
この場合、_beginthread*()を呼ばないと、「正しい挙動」はしてくれない。
なぜなら、Cランタイムをスレッドセーフにする肝心の処理を_beginthread*()がやるから。
ついでに言えば、問題はB.DLLだけの話ではなくて、A.EXEのランタイムに
何を使ってるか? というのも重要。にも関わらず、>>235でその点に
一切触れていない点からも、喪前さんの理解が足りないことが伺える。
0240225
2006/01/28(土) 20:18:06> なぜなら、Cランタイムをスレッドセーフにする肝心の処理を_beginthread*()がやるから。
_beginthread(ex) と _endthead がやるのは、スレッドごとに必要なメモリ
の割り当てと解放を行うことですよね?
_beginthread を使わなかったせいで、ランタイムルーチンを呼び出し時に
そのスレッドではまだメモリが割り当てられてなかったなら、その場で動的に
割り当てれば問題ないでしょう。実際、動的に割り当ててると思うんだけど。
問題なのは、スレッドの終了を知ることが出来なくなるせいで、割り当てた
メモリを解放する機会が得られなくなり、その結果としてメモリリークが発
生する、ということではないの?
_beginthread(ex) を使わないことによって、排他処理的な問題が起こるとは
どこにも書いてないですよね?起こらないとも書いてないけど。
排他処理的な問題が起こると明記されてるのは、シングルスレッド版の
ランタイムを使った場合の方だけです。
マルチスレッド版の方では、メモリリークのことしか書いてないと思う
んですけど。
> ついでに言えば、問題はB.DLLだけの話ではなくて、A.EXEのランタイムに
> 何を使ってるか? というのも重要。にも関わらず、>>235でその点に
> 一切触れていない点からも、喪前さんの理解が足りないことが伺える。
A.EXE は BCB5 で作成、B.DLL は VC6 で作成と書いてます。
理解が足りないのは認めますが。
長文ばかりで申し訳ない。
0241デフォルトの名無しさん
2006/01/28(土) 20:54:270242225
2006/01/28(土) 21:09:14真面目に質問してるつもりなんですが、そういうのが伝わらない
あたりが 2ch のイヤなところですね。
どこかにこの件に関してきちんと解説したウェブサイトなり書籍
があればご紹介頂きたかったですがね。
0243デフォルトの名無しさん
2006/01/28(土) 21:19:39そういうのにいちいち気にしていたら駄目だよw
2chの使い方からまず学んだほうが有効に使えるかも。
当然俺のレスにもレスは要らないぞw(あってもいいけど
0244225
2006/01/28(土) 21:40:13やっぱりそうですか。(^^;
>>235 の結果から、(この検証が正しければ)メモリリークに関しては
処理系依存ということになったわけだし、ドキュメント化されてるわけ
でもないようだから、結局のところ結論なんて出ないんだろうな…。
「A.EXE で作成したスレッドから B.DLL の関数を呼び出すとメモリリークする」
のだとすると、Susie プラグインとか、自分ではメンテナンス出来ないプラグイン
方式の DLL を使うアプリをマルチスレッド化するのは非現実的ということになっ
てしまうのか…。ほとんどの DLL は C ランタイムを使用してるだろうから。
一度作成したスレッドはアプリが終了するまで使い回すようにするしかないの
だろうか…。なんか納得行かないな。
0245デフォルトの名無しさん
2006/01/28(土) 22:06:40スレッドプール使えば"about 70-80 bytes"のリークなんて気にする必要ないのでは?
>>242
MSDNだろ。
0246241
2006/01/28(土) 22:09:502chって憂さ晴らしに最適だよな。
0247デフォルトの名無しさん
2006/01/28(土) 23:06:330248デフォルトの名無しさん
2006/01/29(日) 01:07:13真面目におかしなことばっかり言ってるから相手したくなくなるんだよ。
依存するのは処理系自体ではなくライブラリだし、
アンドキュメントな実装に依存したコードを書くのは無謀。
漏れが言えることは、
「EXE・DLLの両方で同じライブラリ使ってれば、相互に呼び合いしても問題ない」
「泥沼に足突っ込みたくなければ推奨されてるやり方を使え」
それだけ。普通にMSVCRT使えばいい。
それ以上のこと知りたいなら、AdvancedWindowsなりMSDNなりCRTのソースなり
自分で読んで勉強してくれ。スレでいちいち書けるほど単純な話でもない。
0249225
2006/01/29(日) 04:20:43> 「EXE・DLLの両方で同じライブラリ使ってれば、相互に呼び合いしても問題ない」
DLL は他人が作ってるので自分でいじれないし、EXE は GUI の
関係上 BCB しか使えないので。
> 「泥沼に足突っ込みたくなければ推奨されてるやり方を使え」
EXE で作成したスレッドから DLL の関数を呼ぶ場合の推奨されてる
やり方とは?EXE/DLL ともに MSVCRT を使うことですか?
> AdvancedWindowsなりMSDNなりCRTのソースなり自分で読んで勉強してくれ
MSDN と CRT のソースは自分なりに熟読してみたつもりです。
CRT のソースから、>>235 の結果は予想通りでした。
でも、3.の結果は予想通りだけど納得行かない。
BCB5 の C ランタイムライブラリのバグと言うべきなんじゃないだろうか。
仕様で片付けていい問題ではないような…。
AdvancedWindows を読んでもう少し勉強してみます。
0250デフォルトの名無しさん
2006/01/29(日) 09:28:51使ったことないから、どういう事になっているのか知らないし、
それで仕様通りの利用かどうかもわからない。
いずれにせよ、サードパーティのDLL内で、
CreateThread()を多発してない限り、別に大きな障壁になることじゃないよね。
スレッドを多発する場合、スレッドプール使うのは鉄則だから。
0251デフォルトの名無しさん
2006/01/29(日) 18:37:53やなやつだなあ。
まじめに答えてる振り装ってるが不快なことこの上ない。
0252デフォルトの名無しさん
2006/01/29(日) 19:09:23■ このスレッドは過去ログ倉庫に格納されています