-PR-
解決済みの質問
質問:No.7417919
困ってます
お気に入り投稿に追加する (1人が追加しました)
回答数2
閲覧数519
C#のスレッド動作について
下記はスレッドの中で永久ループさせるテストプログラムで、1秒毎にテキストボックス内の数値をインクリメントします。

【問題点1】
※1と※2のコマンドを削除した状態(※3のみ)で正常な動作を期待していたのですが、実際にはフリーズ状態となり、カウント値が表示されません。

※2のApplication.DoEvent()を実装するか、※3の替わりに※1に実装すると正常動作となります。

ExecThread実行中は他の処理を出来なくても、これを抜けた時点で表示処理に移るので表示される筈と思っていたのですが違う様です。

【問題点2】
Invokeの替わりにBeginInvokeを使えばExecThread実行中でも他の処理と並列処理されると思っていたのですが、スレッドを2個用意して試したところInvokeと全く変わらず、やはりフリーズ状態となります。

【問題点3】
ExecThreadを匿名メソッドにすると「フィールド初期化子は、静的でないフィールド、メソッド、又はプロパティ'iCount'を参照できません」のエラーとなり、「iCount」をstatic変数にするとOKになります。
匿名メソッドではインスタンス変数は使えないのでしょうか。

上記3項目についてネットで調べたのですがその様な記述は見当たりませんでした。

何か使い方が間違っているのでしょうか?
間違い点など、ご指摘頂ければ有難いです。 どうぞ宜しくお願いします。

private void ExecWorker() ← スレッド
{
  while (true)
  {
    Invoke(new Exec1Delegate(this.ExecThread)); ← BeginInvokeを使っても症状は同じ
    iCount++;
    Thread.Sleep(1000); ← ※1 このSleepが無いとフリーズする
    Application.DoEvent(); ← ※2 これがあると※1のSleepが無くてもOK
  }
}

delegate void ExecDelegate();
private void ExecThread()
{
  lbThread.Text = iCount.ToString(); ← 匿名メソッドにするとエラーになる
  Thread.Sleep(1000); ← ※3 (※1のSleepと同時実装はしない)
}
投稿日時 - 2012-04-12 22:20:15
質問者が選んだベストアンサー
回答:No.2
WinFormsとマルチスレッドについて詳しく書いてある書籍などを私は知らないのですが……。


とりあえず,「とあるコンサルタントのつぶやき」 ( http://blogs.msdn.com/b/nakama/ ) の一連の記事などは読んでおくとよいと思います。

・マルチスレッド Windows フォームアプリケーションの開発
http://blogs.msdn.com/b/nakama/archive/2009/03/30/windows.aspx
・Part 1. Windows フォームのマルチスレッド処理の基礎
http://blogs.msdn.com/b/nakama/archive/2009/03/31/part-1-windows.aspx
・タスクスレッドの起動方法
http://blogs.msdn.com/b/nakama/archive/2009/04/02/9521640.aspx
・Part 3. タスクスレッドと UI の協調動作
http://blogs.msdn.com/b/nakama/archive/2009/04/07/part-3-ui.aspx
・Part 4. Visual Studio によるマルチスレッドアプリの開発
http://blogs.msdn.com/b/nakama/archive/2009/04/09/part-4-visual-studio.aspx
投稿日時 - 2012-04-17 14:18:21
この回答を支持する
(現在0人が支持しています)
この質問は役に立ちましたか?
0人が「このQ&Aが役に立った」と投票しています
ベストアンサー以外の回答
回答:No.1
基本的に,Invokeは
・元のスレッドをブロックする
・UIスレッドがアイドル状態になったタイミングでデリゲートを実行する
・UIスレッドでのデリゲートの実行が終了した時点で元のスレッドを再開する
という動作になります。


※1を削除すると,ワーカースレッド側で常にInvokeを呼び出すため,
メッセージに応答はしているものの常にInvokeで呼ばれたメソッドを実行している状態に近くなり,
UIの応答が極端に悪くなります。
※1によるSleepは,UIスレッドでの実行間隔を調整することになるため,応答性がよくなる効果をもたらします。


※2はやってはいけません。
Application.DoEvents自体,根本的に使うべきでは無いですし,UIスレッドで使うべき物です。


※3もやってはいけません。
UIスレッドをブロックします。


InvokeのかわりにBeginInvokeを使った場合,元のスレッドをブロックしなくなります。
※1が無い場合,全体として悪化することになります。
これは,ブロックされなくなった結果,UIスレッドにBeginInvokeのリクエストが溜まっていく結果になるためです。
投稿日時 - 2012-04-13 12:43:50
この回答を支持する
(現在0人が支持しています)
お礼
ご丁寧な回答をいただき、有り難うございました。

もっと詳しく勉強したいのですが、お教え頂いたことを解説しているURLか書籍を御存知でしたら紹介して頂けないでしょうか。
投稿日時 - 2012-04-13 13:16:34
もっと聞いてみる
関連するQ&Aはこちら
情報処理の問題で一つわからない点があります http://www.rs.kagu.tus.ac.jp/infoserv/j-siken/H19a2/pm10.html 上記HPの「 d 」の答えなの...
actionscriptのインクリメントで2ずつ増やす方法教えてください。 ...
インクリメントについて C言語のプログラム中に(1)の文(前置演算子)が存在するのですが、(2)の文(後置演算子)に置き換えても構いませんか? if(a) ++a; ・・・(1) if(a) a+...
この他の関連するQ&Aをキーワードで探す
プログラミングのサブカテゴリ
カテゴリ:C・C++
RSS
-PR-
PR
-PR-