C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: ContextSwitchDeadlock の対処法


(過去ログ 120 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■70251 / inTopicNo.1)  ContextSwitchDeadlock の対処法
  
□投稿者/ an (30回)-(2014/03/04(Tue) 15:05:35)

分類:[VB.NET/VB2005 以降] 

Win8.1
VB2008 SP
.NET Framework3.1 SP1
Oracle11g(ODP.NET)

現在、CSVファイルを読み込み、対象のレコードのみをテンポラリテーブルに登録するという処理を
コンソールアプリケーションで作成しているのですが、
処理完了後にConsole.ReadKey()で待機していると
以下のメッセージが表示されることがあります。
(されないこともあるのですが、発生条件については現在調査中です。)

===========================================================
ContextSwitchDeadlock が検出されました。
===========================================================
CLR は、COM コンテキスト 0x9afc50 から COM コンテキスト 0x9afdc0 へ 60 秒で移行できませんでした。
ターゲット コンテキストおよびアパートメントを所有するスレッドが、ポンプしない待機を行っているか、
Windows のメッセージを表示しないで非常に長い実行操作を処理しているかのどちらかです。
この状態は通常、パフォーマンスを低下させたり、
アプリケーションが応答していない状態および増え続けるメモリ使用を導く可能性があります。
この問題を回避するには、すべての Single Thread Apartment (STA) のスレッドが、CoWaitForMultipleHandles のような
ポンプする待機プリミティブを使用するか、長い実行操作中に定期的にメッセージをポンプしなければなりません。
===========================================================

メッセージの詳細を読んでも何となくは分かるのですが、100%は理解できなかったので、
ContextSwitchDeadlockについてWeb検索を行ったところ、
デバッグメニューの例外で表示される例外ダイアログにて表示しないようにできるとあったのですが、
細かい理由は記載されておらず、これが根本的な解決になっているか判断できませんでした。

また、上記現象はデバッガ上で実行した際に発生しますが、
リリースビルドで生成したEXEを同条件で実行した場合は、特に上記エラーは発生しませんでした。

ContextSwitchDeadlockの対処法として、上記の対処法が正しいのでしょうか?
現在マルチスレッド処理にはしていませんが、例えばマルチスレッド化すべきなのでしょうか?

理由も含めて教えて頂けるとより助かります。

引用返信 編集キー/
■70274 / inTopicNo.2)  Re[1]: ContextSwitchDeadlock の対処法
□投稿者/ an (31回)-(2014/03/06(Thu) 17:16:29)
発生条件について、処理を徐々にコメントアウトして確認してみましたが
日によって発生する条件が異なっていたので、特定に至りませんでした・・・。

「メッセージをポンプしなければなりません。」とあったので、
試しにContextSwitchDeadlockが必ず発生するパターンのプログラムの途中でDoeventsを実行するようにしたところ、
ContextSwitchDeadlockが発生しなくなりましたが、これはこれで正しい方法とは思えませんでした。

結論としてはデバッガ上での話という事だと思うので、
デバッグメニューの例外で表示される例外ダイアログにて表示しないようにしました。

解決済み
引用返信 編集キー/
■70288 / inTopicNo.3)  Re[1]: ContextSwitchDeadlock の対処法
□投稿者/ とっちゃん (205回)-(2014/03/07(Fri) 15:18:45)
とっちゃん さんの Web サイト
No70251 (an さん) に返信
> Win8.1
> VB2008 SP
> .NET Framework3.1 SP1
> Oracle11g(ODP.NET)
>
.NET Framework には 3.1 というのはありません。
2.0, 3.0, 3.5 のいずれかになると思いますが、VB2008 だと、3.5 になるのかな?

さて、それはともかくとして...


> 理由も含めて教えて頂けるとより助かります。
>
http://msdn.microsoft.com/ja-jp/library/vstudio/ms172233.aspx
(掲示板からリンクがうまく晴れないことを防止するため、最新のものにリンクしています)
のリファレンスは見てみたでしょうか?

ContextSwitchDeadlock は、MDA(Managed Debugging Assistant:マネージデバッグアシスタント)と呼ばれる特殊なデバッグサポート用の機能です。

ここにもエラーに関する説明が出ていますがこちら。。。もやっぱりわかりにくいですね。

COMは、その内部処理(主にスレッド間やプロセス間での同期処理)のためにウィンドウを持っており、そのメッセージ処理の仕組みを利用して
COM専用のスレッドコンテキストスイッチャーを用意しています。

そのため、必要に応じてメッセージを処理する(DoEvents相当のことを該当スレッドの適切な場所で行う)必要があります。



> 発生条件について、処理を徐々にコメントアウトして確認してみましたが
> 日によって発生する条件が異なっていたので、特定に至りませんでした・・・。
>
これが発生するのは、処理を減らしたり、実行時の状況によって、メッセージを処理する必要があるタイミングが変わるからです。

マシン内で閉じた世界でも、LANなどで外につながっている場合でもその時の状況により
瞬間的な負荷状況が変わります。そのため、実行時の様々な状況によって、ReadKeyを呼び出すタイミングよりも前に
メッセージを処理している場合もあります。

> 「メッセージをポンプしなければなりません。」とあったので、
> 試しにContextSwitchDeadlockが必ず発生するパターンのプログラムの途中でDoeventsを実行するようにしたところ、
> ContextSwitchDeadlockが発生しなくなりましたが、これはこれで正しい方法とは思えませんでした。

正しいかどうかはプログラムに依存するため何とも言えませんが、とりあえずの回避策としてはだめというものではないと思います。
ただし、とりあえず、絆創膏貼ってみました的な対処方法ですが。

ODP.NET は持っていない(そもそもOracleを持っていない)のでわかりませんが、mainメソッドにSTA属性をつけたらうまくいくかもしれません(.NET が良しなに対応してくれる)。
ODP.NETの利用条件(ライセンスではなく、開発サイドの)なども詳しくチェックしてみるといいかもしれません。

引用返信 編集キー/
■70292 / inTopicNo.4)  Re[2]: ContextSwitchDeadlock の対処法
□投稿者/ an (32回)-(2014/03/07(Fri) 17:08:10)
とっちゃんさん、回答ありがとうございます。


No70288 (とっちゃん さん) に返信

> .NET Framework には 3.1 というのはありません。
> 2.0, 3.0, 3.5 のいずれかになると思いますが、VB2008 だと、3.5 になるのかな?

誤記です。
3.5の間違いです。
失礼しました。


> http://msdn.microsoft.com/ja-jp/library/vstudio/ms172233.aspx
> (掲示板からリンクがうまく晴れないことを防止するため、最新のものにリンクしています)
> のリファレンスは見てみたでしょうか?
>
> ContextSwitchDeadlock は、MDA(Managed Debugging Assistant:マネージデバッグアシスタント)と呼ばれる特殊なデバッグサポート用の機能です。
>
> ここにもエラーに関する説明が出ていますがこちら。。。もやっぱりわかりにくいですね。
>
> COMは、その内部処理(主にスレッド間やプロセス間での同期処理)のためにウィンドウを持っており、そのメッセージ処理の仕組みを利用して
> COM専用のスレッドコンテキストスイッチャーを用意しています。
>
> そのため、必要に応じてメッセージを処理する(DoEvents相当のことを該当スレッドの適切な場所で行う)必要があります。

当該サイトは調査した段階で確認していました。
(分かりにくかったです・・・^^;)
COMは使っていないので無関係と思い流し読みしていましたが、
その後再確認した際にポンプというキーワードからDoEventsにたどり着いた次第です。

ちなみに「DoEvents相当」とは例えばどのような処理が当たるのでしょうか?


>>発生条件について、処理を徐々にコメントアウトして確認してみましたが
>>日によって発生する条件が異なっていたので、特定に至りませんでした・・・。
>>
> これが発生するのは、処理を減らしたり、実行時の状況によって、メッセージを処理する必要があるタイミングが変わるからです。
>
> マシン内で閉じた世界でも、LANなどで外につながっている場合でもその時の状況により
> 瞬間的な負荷状況が変わります。そのため、実行時の様々な状況によって、ReadKeyを呼び出すタイミングよりも前に
> メッセージを処理している場合もあります。

やはりそういう事なのですね・・・。
この手の現象は目に見えにくいので本当に困っていました。



>>「メッセージをポンプしなければなりません。」とあったので、
>>試しにContextSwitchDeadlockが必ず発生するパターンのプログラムの途中でDoeventsを実行するようにしたところ、
>>ContextSwitchDeadlockが発生しなくなりましたが、これはこれで正しい方法とは思えませんでした。
>
> 正しいかどうかはプログラムに依存するため何とも言えませんが、とりあえずの回避策としてはだめというものではないと思います。
> ただし、とりあえず、絆創膏貼ってみました的な対処方法ですが。

絆創膏・・・同感です。
しかも、コンソールアプリケーションなのにForm関連クラス(※)に定義してあるDoEventsを使うのは抵抗がありすぎでした。

※DoEventsでオブジェクトブラウザで検索したら、
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoEvents()
System.Windows.Forms.Application.DoEvents()
の2つが出てきたので。


> ODP.NET は持っていない(そもそもOracleを持っていない)のでわかりませんが、mainメソッドにSTA属性をつけたらうまくいくかもしれません(.NET が良しなに対応してくれる)。
> ODP.NETの利用条件(ライセンスではなく、開発サイドの)なども詳しくチェックしてみるといいかもしれません。

ODP.NETの利用条件の件、了解しました。
そちらの観点でも調査を行おうと思います。

とりあえず、手始めにSTA属性を付けて確認してみようと思いますが、
現在何もmainメソッドに何の属性も付けていない状態です。

ちなみに
http://dobon.net/vb/dotnet/form/stathread.html
によると
> ただしVB.NETでは、MainメソッドにSTAThreadAttribute属性を付けなくてもSTAになります。
とありました。
まぁ物は試しでSTA、MTA両方試してみようと思います。
結果は後日報告させていただきます。

引用返信 編集キー/
■70295 / inTopicNo.5)  Re[3]: ContextSwitchDeadlock の対処法
□投稿者/ とっちゃん (208回)-(2014/03/07(Fri) 18:39:20)
とっちゃん さんの Web サイト
No70292 (an さん) に返信
> 当該サイトは調査した段階で確認していました。
> (分かりにくかったです・・・^^;)
> COMは使っていないので無関係と思い流し読みしていましたが、
> その後再確認した際にポンプというキーワードからDoEventsにたどり着いた次第です。
>
> ちなみに「DoEvents相当」とは例えばどのような処理が当たるのでしょうか?
>
GUIアプリのApplication.Run()を呼び出す。
MessageBox API(クラスもOK)で、メッセージを出す。
という形で、DoEventsがやってることと同じことができます。

ま、面倒ですけどねw
#DoEventsが内部で処理してる仕組みのお話については割愛


> >>「メッセージをポンプしなければなりません。」とあったので、
> >>試しにContextSwitchDeadlockが必ず発生するパターンのプログラムの途中でDoeventsを実行するようにしたところ、
> >>ContextSwitchDeadlockが発生しなくなりましたが、これはこれで正しい方法とは思えませんでした。
>>
>>正しいかどうかはプログラムに依存するため何とも言えませんが、とりあえずの回避策としてはだめというものではないと思います。
>>ただし、とりあえず、絆創膏貼ってみました的な対処方法ですが。
>
> 絆創膏・・・同感です。
> しかも、コンソールアプリケーションなのにForm関連クラス(※)に定義してあるDoEventsを使うのは抵抗がありすぎでした。
>
> ※DoEventsでオブジェクトブラウザで検索したら、
> Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoEvents()
> System.Windows.Forms.Application.DoEvents()
> の2つが出てきたので。
>
ちなみに、どっちを呼び出しても最終的にやってることは同じなので好きなほうを呼び出していいと思います。

>
>>ODP.NET は持っていない(そもそもOracleを持っていない)のでわかりませんが、mainメソッドにSTA属性をつけたらうまくいくかもしれません(.NET が良しなに対応してくれる)。
>>ODP.NETの利用条件(ライセンスではなく、開発サイドの)なども詳しくチェックしてみるといいかもしれません。
>
> ODP.NETの利用条件の件、了解しました。
> そちらの観点でも調査を行おうと思います。
>
> とりあえず、手始めにSTA属性を付けて確認してみようと思いますが、
> 現在何もmainメソッドに何の属性も付けていない状態です。
>
> ちなみに
> http://dobon.net/vb/dotnet/form/stathread.html
> によると
>>ただしVB.NETでは、MainメソッドにSTAThreadAttribute属性を付けなくてもSTAになります。
> とありました。
> まぁ物は試しでSTA、MTA両方試してみようと思います。
> 結果は後日報告させていただきます。
>

改めて、ContextSwitchDeadlock MDAの説明見たら、MTAにするか、メッセージポンプを動かせってありますね。
ということで、MTAがいいのかもしれません。

この辺りは、実際にいろいろ試してみないと何とも。。。という部分もありますので。

引用返信 編集キー/
■70319 / inTopicNo.6)  Re[4]: ContextSwitchDeadlock の対処法
□投稿者/ an (33回)-(2014/03/10(Mon) 15:25:15)
No70295 (とっちゃん さん) に返信


> GUIアプリのApplication.Run()を呼び出す。
> MessageBox API(クラスもOK)で、メッセージを出す。
> という形で、DoEventsがやってることと同じことができます。
>
> ま、面倒ですけどねw

なるほど。
結局はDoEventsと同様にForms方面の話になってしまうわけですね。


> ちなみに、どっちを呼び出しても最終的にやってることは同じなので好きなほうを呼び出していいと思います。
やっぱりそうですか。
まぁ仮に呼ぶとしたら、System.Windows.Forms.Application.DoEvents()ですかね?
インスタンス生成しなくても呼べますし。



> 改めて、ContextSwitchDeadlock MDAの説明見たら、MTAにするか、メッセージポンプを動かせってありますね。
> ということで、MTAがいいのかもしれません。
>
> この辺りは、実際にいろいろ試してみないと何とも。。。という部分もありますので。

STA・MTAについてそれぞれ数回試してみました
STAにしても現象は変わりませんでした。
やはり省略はSTAのようですね。
MTAにしたらContextSwitchDeadlockが出なくなりました。
全ての環境においてMTAにすれば良いというわけでは無いかもしれませんが、
今のところはこちらの環境ではMTAによる悪い影響は出ていません。
まだテストフェーズまで進んでいないので、MTAにした状態で進めていこうと思います。

MTAについてまだ完全に理解した訳ではありませんが、例外無視対応よりすっきりしました。
暇を見つけてMTA・STA等を理解しようと思います。

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

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -