dllが死んだあとのスレッドの行方

[戻る]
roccy 2005/07/11(月) 00:00:46
dllの中でスレッドを生成し、起動しています。
通常、dllは、正常に終了するので終了する前にスレッドを停止しています。
あるとき、dllが正しく終了しなかった場合にスレッドが生きたままになっている
生きたままのスレッドが生成元のdll(すでに死んでいるdll)をコールして
アプリエラーになっているような気がしています。
以下のやり方で問題があれば、ご指摘ください。
1.DLLのロード
2.スレッドクラスの作成
  スレッドの起動(_beginthreadex)
  イベントの作成(CreateEvent)
3.DLLの異常等による終了
4.スレッドクラスのデストラクタ
  イベントの終了
  スレッド未終了時スレッドの強制終了(TerminateThread)
  ハンドラのクローズ(CloseHandle)

・デストラクタでスレッドの終了することは問題ないでしょうか?
・スレッドが起動中に強制終了させていますが、スレッドを強制終了することは、
 一般なことなのでしょうか?
・すでに死んでいるdllがコールされないような方法はありますか?

ちなみに開発環境は、
Windows2000
VC++6.0
WindowsAPI
です。

情報が少ないかもしれませんが、ご存知の方、ご教授お願いします。

シャノン 2005/07/11(月) 10:46:58
そもそも、「DLL が死ぬ」とはどういう事態なのでしょうか。
何らかのエラーによって、ロードされた DLL が勝手にアンロードされる?
そのような話を聞いたことはありませんが、どのような原因により引き起こされるので
しょうか?

> ・デストラクタでスレッドの終了することは問題ないでしょうか?
> ・スレッドが起動中に強制終了させていますが、スレッドを強制終了することは、
>  一般なことなのでしょうか?

実行中のスレッドを TerminateThread で強制終了させることは、推奨される手段ではあ
りません。
ただし、DLL が死ぬ(という事象がどういうものだかいまいちわかりませんが、アンロー
ドされるということであれば)ような重要な異常事態下にあっては、推奨されるのされな
いのと言っている場合ではないので、緊急手段としてはあり得るものだと思います。

デストラクタでスレッドを終了させることの是非についても、上記のことが言えます。
つまり、正常系におけるクラスのデストラクタで TerminateThread を使うことは推奨さ
れませんが、異常事態下においては検討に値する手段だということです。
正常な状態では、スレッドの強制終了は望ましくありませんから、スレッドに何らかの
「終了せよ」という信号(フラグなりイベントなりメッセージなり)を送って、スレッド
が自然終了するまで待機するということになるでしょう。
これがパフォーマンス的に許容できるのであれば、デストラクタ中でスレッドを終了させ
ることは問題ありません。
あるいは、スレッドに終了信号を送ったら、スレッドは放っておいても正常に終了すると
いう期待により、終了を待たずにデストラクタを抜けてしまうというのもありでしょう。
そういう挙動をしても問題の無い設計になっているのであれば、これでも構わないと思い
ます。

popo 2005/07/11(月) 11:58:14
スレッドクラスのオブジェクトは dll 内の静的変数なのかな?
で、DllMain でのデタッチ通知とクラスのデストラクタの両方に
スレッド終了のための処理がある、てこと?

DLL のデタッチ通知と DLL 内変数のデストラクタは _DllMainCRTStartup から
順番に同一スレッドで呼び出されるだけのものなので、
デストラクタが呼び出されるなら、その前にデタッチ通知は行われているはず。
何か異常が起きて DLL がデタッチ通知無しにアンロードされてしまうというなら
デストラクタも動かないですよ?

#「DLL が死ぬ」の意味は、やっぱり誰もわからないと思います(^^;
#スレッドやモジュールについてちゃんと理解してるなら、
#もう少し具体的に説明してほしいところですが...

・・・ 2005/07/11(月) 12:50:42
直接の回答ではなくて、感想になるかも知れませんが
何点か指摘させて下さい。

1.↓のような感触がるのであれば(なくとも)、対応するコードを入れる。
>生きたままのスレッドが生成元のdll(すでに死んでいるdll)をコールして
>アプリエラーになっているような気がしています。

すなわち、スレッドルーチンの方に↓のようなコードがありますか?
[手順1]dll(の関数)をコールする
[手順2]正常であれば、そのまま正常処理を続行する。
  何らかの異常があれば、「_endthread」でスレッドを終了する。
#何らかのメッセージを出してからの終了の方が尚良し。
#あくまでも、スレッドの方は正常にまだ動いていることが前提。

2.「TerminateThread」は通常でも、スレッドの終了としては問題が
あるようです。(MSDN等を参照)その上さらに、スレッドを生成
した「dll」が機能していないにも関わらず、「dll」から使うとしたら
まともに動くのですか?
#dllをロードした所に、ハンドルのコピーがあれば可能かとも考えます。

3.dllの異常原因の探求も怠りなくして頂きたい。

4.私の知識不足かも知れませんが、「スレッドクラスの作成」?
↑の意味が分からないです。「WindowsAPI」で「クラスの作成」?
「クラス」って、オブジェクト指向のC++(問題はあると思いますが)
とか、JAVAで使われてはいるようですが・・・。
Cインターフェースの「WindowsAPI」で作れるのですか? それとも
「スレッドクラスの作成」は「スレッドオブジェクトの作成」でしょうか?
だから、「デストラクタでスレッド・・・」の意味も分かりません。

5.「dll」単独、「スレッド」単独でも質問が来ています。
ですから、「dll」からの「スレッドの作成」はかなりの難問です。
>以下のやり方で問題があれば、ご指摘ください。
とのことですが、自信を持って指摘できる方はそう多くないと思います。
#私もこのような使い方をしてませんので、自信はありません。
  

>・デストラクタでスレッドの終了することは問題ないでしょうか?
一般的な終了処理であれば、できるのであればメモリーリークの
問題が発生するので、した方が良いかと思います。

>・スレッドが起動中に強制終了させていますが、
>スレッドを強制終了することは、一般なことなのでしょうか?
通信相手が機能してないときは、コードとしては「TerminateThread」
を使うことがあると思います。しかし、一般的かと聞かれると・・・?
いつでも正常とは限らないので、コードとしては必要と思います。
しかし、正常でないときの原因の調査が肝要と思います。

>・すでに死んでいるdllがコールされないような方法はありますか?
???
上で指摘した[手順1、2]のコードを普通であれば入れると思いますが。

あと、要望として(要点をまとめた)ソースも提示して下さい。
私が理解できるかどうかは別としても、ソースがあれば具体的に
解決できる可能性も高まる思います。

renbar 2005/07/11(月) 15:32:19
面倒なので、読む側で「です・ます」調に読み替えてくださいね。(笑)

exe や dll はコードを実行しない。
exe や dll 内のコードを実行するのはスレッドだ。
スレッド無しにコードは勝手に動かない。

exe が WinMain 関数を、dll が DllMain 関数を実行するのではない。
スレッドが exe 内の WinMain 関数や dll 内の DllMain 関数を実行するのだ。

exe が死んだ、dll が死んだ、などと表現することはよくあるが、
それは通常、exe や dll のコードを実行しているスレッドがメモリアクセス
違反で停止したり、無限ループに陥っていることを指す。

今回の「dll が死んだ」表現には2〜3種類の解釈ができる。

1. dll を実行中の別のスレッドが異常停止/無限ループしている
2. dll 内のコードを実行した別のスレッドが dll 内メモリを破壊してしまった
3. dll がアンロードされてメモリ上から存在しなくなっている

2. は「死んだ」という表現にはちょっとそぐわないかもしれない。
メモリ破壊の結果、1. に至って初めて「死んだ」というのが普通だろう。

ただ、いずれのケースにしろ一般的には救済不可能だと思う。
3. のケースではスレッド制御関数自身が dll モジュール内に書かれているコードなら
(今回のはたぶんそうだが)、dll 関数を呼ばないようにするもへったくれもない。
dll がアンロードされた瞬間、直ちにメモリアクセス違反になるだろう。
なにしろスレッド制御関数内に書かれているコードもアンロードされてしまうのだか
ら。
それ以外のケースでは、正常に動作しているスレッドは、
そのまま問題なく dll 内コードを実行できるかもしれないし、
実行できなくなるかもしれない。

さて、「dll が死んだ」とは、どういう状況ですかね?

renbar 2005/07/11(月) 15:59:30
続けて、

DllMain 関数内ではあまり複雑なことをしないほうがいい。
例えば、スレッドの起動や終了待ち合わせ。

スレッドを起動すれば、起動されたスレッドは制御関数の実行を開始する前に
DLL_THREAD_ATTACH を引数として DllMain 関数を呼び出すだろう。
待機しているスレッドが終了すれば、そのスレッドは制御関数を抜けた後で
DLL_THREAD_DETACH を引数として DllMain 関数を呼び出すだろう。

スレッドの起動元や待ち合わせ元がまだ DllMain 関数を実行している最中に、
再び起動されたスレッドがこのような DllMain 関数呼び出しの動作をするのだ。
僕はそんな複雑なのはいやだ。
すなおにスレッド起動用関数と終了用関数をエクスポートして、利用する側の
モジュールに下駄を預けちゃうね。

renbar 2005/07/11(月) 16:06:33
ごめん、DllMain 関数はシステムによってシリアライズされるから
同時実行はされない。
だから、そもそも DllMain 関数ではスレッドの終了待ちはできない。
たぶんデッドロックする。

シャノン 2005/07/11(月) 16:46:21
> たぶんデッドロックする。

たぶんぢゃなくて確実にします(やったことあります)。

renbar 2005/07/11(月) 17:06:21
> たぶんぢゃなくて確実にします(やったことあります)。

(´∀`σ)σ

もしかして、質問者はまさにこの類のデッドロックを「死んだ」とか言ってるのかな
ぁ?
...違うか。

popo 2005/07/12(火) 09:33:59
システム見えの”真の DllMain”は _DllMainCRTStartup のほうだから、
クラスのデストラクタでも待ち合わせは不可能ですね。
それで、TerminateThread なのか。

デタッチ時の _DllMainCRTStartup に制御が渡った時点で、
もしもまだ対象スレッドが動作していたら、そのスレッドはもはや
穏便に終了することなど絶対に無く、メモリ保護違反になるか、
TerminateThread で手足をもぎ取られて終了するしかない運命だな。

roccy 2005/07/18(月) 17:08:12
皆さん、貴重なご意見ありがとうございます。

>シャノンさん
「DLLが死ぬ」とは、アンロードされたということです。
ハンドラのクローズをすることでスレッドループから抜けてくるはず
なのですが、
スレッドの途中で止まったまま、WaitForSingleObjectへ来ないため、
ハンドラをクローズしてもスレッドループから抜けてこないことが
わかりました。
アンロードされたあともスレッドが終了できない状態になっていました。

本来は、正しくスレッドが終了するはずなのですが、
「ある状態」のときにスレッドが終了しないのです。
そのため、デストラクタでスレッドが起動中なら、
強制終了しようとしています。
「ある状態」は、異常事態ではなく、普通に起こりうる
状態なので、スレッドが終了するのを待つ必要があります。

パフォーマンス的に許容されるので、スレッドをデストラクタで
終了させているのは、そのままにしておきます。
こんなやり方みんなしているのか不安でしたので。

>popoさん
>スレッドクラスのオブジェクトは dll 内の静的変数なのかな?
>で、DllMain でのデタッチ通知とクラスのデストラクタの両方に
>スレッド終了のための処理がある、てこと?
スレッドクラスは、単にスレッドを持っているクラスです。
dll 内の静的変数ではありません。
デタッチ通知の意味はよく知らないのですが、
終了処理は、デストラクタで行っています。

>・・・さん
異常終了というのは、例外を発生させて終了させています。
一つ分かったのですが、例外を発生させた場合、
デストラクタが呼ばれないことがわかりました。
try{
    AAA aaa;
}
catch(...)
{
    FuncA();
}
上記の場合、
FuncAでAAAのデストラクタがコールされるはずですが、
ちなみに、AAAのデストラクタでスレッド終了処理が入っています。

>renbar さん
ずばり、その通りでした。
エラーダイアログが表示されるのですが、原因がわからなかったので、
「死んだ」という表現を使っていました。
1.の「スレッドが異常停止してしまっている」ため、「死んだ」ようです。
そのまま、dllがアンロードされてスレッドだけが生き残っており、
これが根本原因でした。

-----
対処方法としては、
1.スレッド終了時には、終了通知を送る。
2.スレッドが終了していない場合(「ある状態」の場合)は、
 スレッドが終了するのを待つ。
ここで気になるのが、
・デストラクタでスレッドが終了するのを待っているが、
 「ある状態」は、長い時間そのままであることもある。
 そのため、INFINITEで永久に待つことになるが、
 デストラクタで処理が止まった状態になってしまうが、
 「ある状態」から復旧したとき、そのあとの処理が
 正しく行われるのでしょうか?
・例外を発生させた場合、デストラクタが呼ばれない
 ようですが、本当にそうなのですか?ブレークを張ってても
 ブレークで止まりませんでした。

----
皆さんのお陰で解決しそうです。
ありがとうございます。

シャノン 2005/07/18(月) 17:18:14
> 「DLLが死ぬ」とは、アンロードされたということです。

「DLL 内でなんらかの異常が発生した場合に、勝手にアンロードされる」のでしょう
か。そんなことがあるとは思えません。
「自分で意図的にアンロードしたのに、スレッドが上手いこと終了しない」ということ
であれば、「スレッドを終了してからアンロードさせてください」ということになりま
す。

> ハンドラのクローズをすることでスレッドループから抜けてくるはず
> なのですが、
> スレッドの途中で止まったまま、WaitForSingleObjectへ来ないため、
> ハンドラをクローズしてもスレッドループから抜けてこないことが
> わかりました。

ハンドラ?
ハンドル(hThread)をクローズ(CloseHandle)ことを言ってますか?
覚えておいてください。
「スレッドハンドルをクローズしても、そのスレッドが即座に終了することはありませ
ん」。
ついでに言うと、クローズしたハンドルを WaitForSingleObject に渡しちゃダメっす
よ。

> 異常終了というのは、例外を発生させて終了させています。
> 一つ分かったのですが、例外を発生させた場合、
> デストラクタが呼ばれないことがわかりました。
> try{
>     AAA aaa;
> }
> catch(...)
> {
>     FuncA();
> }
> 上記の場合、
> FuncAでAAAのデストラクタがコールされるはずですが、

少なくともこのコードの通りでは、FuncA の中で aaa のデストラクタが呼ばれることは
ありえません。
どこで例外を発生させています?

roccy 2005/07/18(月) 17:33:09
>「自分で意図的にアンロードしたのに、スレッドが上手いこと終了しない」ということ
>であれば、「スレッドを終了してからアンロードさせてください」ということになりま
>す。
その通りです。
意図的にアンロードしていたのですが、スレッドが終了していないとは、
思っていませんでした。

>「スレッドハンドルをクローズしても、そのスレッドが即座に終了することはありませ
ん」。
スレッドループから抜けてこないのは、「ある状態」の場合に抜けてこないので、
スレッドハンドルをクローズしても、「ある状態」から復旧しない限り、
永久にループから抜けてきません。

try
{
    AAA aaa;

}
catch(...)
{
    FuncA();
}

roccy 2005/07/18(月) 17:35:33
回答、ありがとうございます。
すいません、途中で送信してしまいました。
例外を発生させているのは、
try
{
    AAA aaa;
    throw e; // ←ココです。
}
catch(...)
{
    FuncA();
}

n 2005/07/18(月) 18:07:09
(スレの趣旨と関係ないです)

> 「DLL 内でなんらかの異常が発生した場合に、勝手にアンロードされる」
> のでしょうか。そんなことがあるとは思えません。

SetWindowsHookEx + WH_MOUSE で他のアプリケーションのアドレス空間にロードした
DLLは、その内部で例えばアクセス違反を起こすと、ロード先のアプリケーションは
無事なまま、アンロードされます。

シャノン 2005/07/18(月) 19:08:41
> 例外を発生させているのは、
> try
> {
>     AAA aaa;
>     throw e; // ←ココです。
> }
> catch(...)
> {
>     FuncA();
> }

この場合、

> FuncAでAAAのデストラクタがコールされるはずですが、
> ちなみに、AAAのデストラクタでスレッド終了処理が入っています。

aaa のデストラクタは、throw の後、catch の前に呼ばれます。
FuncA が呼ばれる時点では、既にデストラクタは完了しています。

> SetWindowsHookEx + WH_MOUSE で他のアプリケーションのアドレス空間にロードした
> DLLは、その内部で例えばアクセス違反を起こすと、ロード先のアプリケーションは
> 無事なまま、アンロードされます。

そうなんですか。知りませんでした。ありがとうございます。

n 2005/07/19(火) 08:05:19
> ロード先のアプリケーションは無事なまま、アンロードされます。

これはXPの場合でした。
Meでやったらロード先のアプリケーションごと死んでエライことになりました(汗

・・・ 2005/07/19(火) 13:05:30
再度、回答ではなくて、感想になるかも知れませんが・・・。

1.roccyさんが意図したとおりにプログラムが動かないのであれば
原因が「dll」にあるのか、それとも「スレッド」にあるのか
はたまた、両方の併用にあるのか、切り分けて欲しいと思いました。
つまり、「dll」を使わず直接「スレッド」を生成したときは
どうなるのか、結果が欲しいと思いました。
前回の感想「5.」でも思いはにじませましたが、明記した方が
良かったのでしょうね。

2.確認ですが、「dll」において「MFC」のようなクラスを作成し
「スレッド」の処理をするということですね?

>デストラクタでスレッドが終了するのを待っているが、
[1]待つことが、仕様としてもプログラムとしても不都合がなければ、
それでも可と思います。通常は↓になるのでしょうか(終了の検出)
http://kkkon.hp.infoseek.co.jp/tips/VC/beginthread.shtml

[2]あと、GetExitCodeThread なんていうのはどうでしょうか。
スレッドが終了していないのであれば、是非もなく.TerminateThread
スレッドでCランタイムを使わないのであれば、
CreateThread(・・・CREATE_SUSPENDED、)
ResumeThread
ExitThread
を使うことになると思いますが・・・。

>「ある状態」から復旧したとき、そのあとの処理が
>正しく行われるのでしょうか?
「ある状態」・・・?、これも、難しい質問ですね。
だいたい、具体的なソースを提示してくれていません。
#具体的なソースがれば、必ず解決する訳ではありませんし、
#守秘義務のようなものもあるかも知れませんが・・・。

3.要望としては、roccyさんの趣味の範囲であれば、不具合の
原因が特定できなくても良いと思いますが、仕事であれば
是非、原因を突き止めて欲しく思います。

roccy 2005/07/19(火) 22:50:51
[[解決]]
・・・さん、ありがとうございます。

>1.roccyさんが意図したとおりにプログラムが動かないのであれば
>原因が「dll」にあるのか、それとも「スレッド」にあるのか
>はたまた、両方の併用にあるのか、切り分けて欲しいと思いました。
>つまり、「dll」を使わず直接「スレッド」を生成したときは
>どうなるのか、結果が欲しいと思いました。
>前回の感想「5.」でも思いはにじませましたが、明記した方が
>良かったのでしょうね。
スレッドが終了していなかったのが原因です。
「dll」を使っても、使わなくても同様の結果になります。

>2.確認ですが、「dll」において「MFC」のようなクラスを作成し
>「スレッド」の処理をするということですね?
そのとおりです。

>>「ある状態」から復旧したとき、そのあとの処理が
>>正しく行われるのでしょうか?
>「ある状態」・・・?、これも、難しい質問ですね。
>だいたい、具体的なソースを提示してくれていません。
>#具体的なソースがれば、必ず解決する訳ではありませんし、
>#守秘義務のようなものもあるかも知れませんが・・・。
曖昧な言い方をしてしまったことが問題を拡大してしまったようです。
「ある状態」とは、ダイアログを表示してオペレータの入力を待っている状態です。
ダイアログを表示するとスレッドが停止する仕様になっているのです。
普通は、ダイアログを表示したあと、「はい」「いいえ」を
すぐに押すのですが、押さずにずっと待っていると
スレッドが終了する前に、メインのスレッドが終了してしまう状況に
陥ってしまっていたのです。


>3.要望としては、roccyさんの趣味の範囲であれば、不具合の
>原因が特定できなくても良いと思いますが、仕事であれば
>是非、原因を突き止めて欲しく思います。
原因は、スレッドが終了していないことが原因です。
スレッドが終了していないのは、「ある状態」になっていることが
原因です。

#まだ、いくつか疑問点がありますが、前述のとおりの
対処で解決いたしました。すべて、皆さんの貴重なご意見の
お陰です。

>対処方法としては、
>1.スレッド終了時には、終了通知を送る。
>2.スレッドが終了していない場合(「ある状態」の場合)は、
> スレッドが終了するのを待つ。
>ここで気になるのが、
>・デストラクタでスレッドが終了するのを待っているが、
> 「ある状態」は、長い時間そのままであることもある。
> そのため、INFINITEで永久に待つことになるが、
> デストラクタで処理が止まった状態になってしまうが、
> 「ある状態」から復旧したとき、そのあとの処理が
> 正しく行われるのでしょうか?
>・例外を発生させた場合、デストラクタが呼ばれない
> ようですが、本当にそうなのですか?ブレークを張ってても
> ブレークで止まりませんでした。

ありがとうございました。

シャノン 2005/07/20(水) 09:41:42
> 「ある状態」とは、ダイアログを表示してオペレータの入力を待っている状態です。
> ダイアログを表示するとスレッドが停止する仕様になっているのです。
> 普通は、ダイアログを表示したあと、「はい」「いいえ」を
> すぐに押すのですが、押さずにずっと待っていると
> スレッドが終了する前に、メインのスレッドが終了してしまう状況に
> 陥ってしまっていたのです。

サブスレッドでモーダルダイアログを表示しているけれど、スレッドが違うので、メイン
スレッドから見るとモードレスダイアログになってしまっている状況かしら?

・・・ 2005/07/20(水) 16:02:45
>シャノンさんへ

他の掲示板からの抜粋ですが・・・(過去ログになっているので)
ご存知とは思いますが、念のためモーダルダイアログの仕様です。
>junさんの報告から
ダイアログ開始時に「オーナーウィンドウを無効にする」
(MSDNでWin32APIのDialogBoxマクロ参照)
>ジェットさんの報告から
DialogBox マクロでダイアログを作成すると、オーナーウィンドウは
確実に無効化されます(WM_ENABLE メッセージが来ます)。
また、内部で独自のループ処理をしているので、ダイアログを閉じるまで
制御が戻りません。

この原則はスレッドが違っても変わらないようです。
ただし、今回のケースで確かめた訳ではないです。
MFCのGUIスレッドで、独立したウィンドウの動きを
期待して、モーダルダイアログを作ったときの場合ですが。

#質問した方が、それなりに目処がついたのは喜ぶべきことと
#考えますが、回答する方として多少の不完全燃焼は残りますね。

シャノン 2005/07/20(水) 16:12:09
> この原則はスレッドが違っても変わらないようです。

そうですか。
スレッドが違ってもモーダルはモーダルなのですね。
ご指摘ありがとうございます。

roccy さんの

> 「ある状態」とは、ダイアログを表示してオペレータの入力を待っている状態です。
> ダイアログを表示するとスレッドが停止する仕様になっているのです。
> 普通は、ダイアログを表示したあと、「はい」「いいえ」を
> すぐに押すのですが、押さずにずっと待っていると
> スレッドが終了する前に、メインのスレッドが終了してしまう状況に
> 陥ってしまっていたのです。

この書き込みから、「ダイアログが開いているのにメインウィンドウが閉じられてしまっ
た」というケースを想定しての書き込みでした。
が、そうでないとすると…

> スレッドが終了する前に、メインのスレッドが終了してしまう状況に
> 陥ってしまっていたのです。

これがバグでなく仕様に起因するものならば、なんだかおかしい気がします。

> 「ある状態」とは、ダイアログを表示してオペレータの入力を待っている状態です。

通常、このような場合、オペレータが入力した値を受けて後続の処理を行うため、
メインスレッドの方では精々、バックグラウンド処理くらいしかできないのが定石である
と思います。
それを、オペレータが入力しなくてもメインスレッドが終了できるということは、メイン
スレッドとサブスレッドに何ら関係が無いということに…?
そもそも、マルチスレッドにする必要があったのかどうか、見直すべきではあるまいか?
 と思うのですが、勘繰り過ぎでしょうか。

・・・ 2005/07/20(水) 21:21:20
>シャノンさんへ

>これがバグでなく仕様に起因するものならば、なんだかおかしい気がします。
多分、「dllが死んだあとのスレッドの行方」の掲示板スレ主も
この辺りの仕様で、難題にぶつかったような気がします。
それで、示された対処方法で対応しようとしているのではと思います。
#あくまでも、推測の域をでませんが・・・・

仕様については、モーダルともモードレスとも明言していません。

選択肢として、モードレスが候補にあがる場合もあるようです。
#著作権で訴えられないかと、多少の不安を覚えつつ・・・。
やはり、↓は他の掲示板からの抜粋ですが。(名前は変更)

○ ×2003/12/×× 
「○ ×」と申します。

MessageBox()を表示すると、
ここで処理が中断しますが、
表示しまたまま処理が次のステップへ
進むようなオプションはないでしょうか?

↑の質問に対しての解決策として、
次の3つの方法が提案されています
1.マルチスレッド
2.モードレスダイアログ
3.新しいプロセスを生成して、そこで表示

それで、話を今回のケースに戻しますが
1.モードレスの場合も考えられますし、
2.背景のオーナーウィンドウが無効のまま、
プライマリースレッドの方が、サブスレッドにお構いなく、
処理を進めた結果とも考えられます。

2.も考えられるの理由については、プライマリースレッドの方は
ユーザーインターフェースからのイベントを受付られないだけで、
他の処理はできると思うので。(実際には確かめていません)

#私としては、第三のGUIスレッドも考えられるのでは考えます。

話にまとまりがなく申し訳ないです。

#この掲示板の質問者は解決しているので、続きは他の適切な
#ところを案内して頂ければ、浅学な知識が役に立つかも
#知れませんが・・・。

シャノン 2005/07/20(水) 21:54:29
> 2.も考えられるの理由については、プライマリースレッドの方は
> ユーザーインターフェースからのイベントを受付られないだけで、
> 他の処理はできると思うので。(実際には確かめていません)

確かに可能性としてありえなくはないですが、それはつまり、ユーザの入力に時間制限が
つくということなので、ゲームでもない限りは、「普通はそんな不親切な(スレ主さんゴ
メンナサイ)インターフェイスは作らないだろう」との予想のもと、先のような書き込み
をした次第です。

が、真相がどうであれ、既に解決したスレをこれ以上伸ばすのも申し訳ありませんので、
これにて一旦閉幕とさせていただきたく存じます。

roccy 2005/07/21(木) 22:22:28
[[解決]]
みなさん、多くのご意見ありがとうございます。

スレッドとダイアログ表示の詳細については、あまりお答えできませんが、
1.ダイアログを表示させるメインスレッド
2.内部処理をするスレッド
3.メインスレッドに対して処理するスレッド
大きく3つに分かれます。
2のスレッドは、1のスレッドから起動されます。
3のスレッドは、2のスレッドから起動されます。
あるボタンを押すと、1のスレッドがダイアログを表示します。
2のスレッドは、ダイアログが表示されると停止します。
同様に3のスレッドもダイアログが表示されると停止します。
そして、2のスレッドが3のスレッドを終了させようとした
瞬間にボタンを押すと、3のスレッドが停止したまま、
終了させようとしてしまいます。
こういった作りが問題であるのかもしれませんが、
ひとまず、皆さまのおかげで解決いたしました。

ありがとうございました。

古いスレッドには追加発言できません。