using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace try1
{
public partial class Form1 : Form
{
volatile bool start_a = false;
volatile bool start_b = false;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (start_a == false)
{
button1.Text = "Running";
start_a = true;
Thread thread2 = new Thread(new ThreadStart(th1));
thread2.Start();
}
else
{
button1.Text = "Click to start";
start_a = false;
}
}
void th1()
{
int a=0;
while (start_a==true)
{
label1.Invoke((MethodInvoker)(() => label1.Text = Convert.ToString(a)));
Thread.Sleep(50);
a++;
}
}
void th2()
{
int b = 0;
while (start_b == true)
{
label2.Invoke((MethodInvoker)(() => label2.Text = Convert.ToString(b)));
Thread.Sleep(5000);
b=b+5;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (start_b == false)
{
button2.Text = "Running";
start_b = true;
Thread thread2 = new Thread(new ThreadStart(th2));
thread2.Start();
}
else
{
button2.Text = "Click to start";
start_b = false;
}
}
private void quitting(object sender, FormClosingEventArgs e)
{
start_a = false;
start_b = false;
}
}
}
答えて
問題が作成されたスレッド以外のスレッドでUIコントロールを更新していると思われます。私はあなたがこれを見なければならないと思う:How to update the GUI from another thread in C#?またはここに:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx例のいくつかは必要以上に複雑ですが、その要点は、あなたが作成された同じスレッドからコントロールを更新する必要があることです。 Control.InvokeRequiredは、注意を払うものです。
エラーの発生場所と時期についてさらに詳しく知る必要があります。コードを見て私の最初の推測では、フォームを閉じるときに例外を取得しているということです。終了イベントハンドラは、start_a
とstart_b
をfalseに設定しますが、フォームがクリーンアップコードを実行する前にバックグラウンドスレッドが終了するまで待機しません。これで、バックグラウンドスレッドとフォームクリーンアップの間に競合状態が発生しました。このクリーンアップコードはウィンドウハンドルを解放するので、バックグラウンドスレッドが5秒後に起動し、テキストの変更をUIスレッドに呼び戻そうとしたときにエラーが発生します。
問題を解決する最も簡単な方法は、ライブのバックグラウンドスレッドをJoin()にして、フォームが終了する前に終了するのを待つことです。より正確でより複雑な方法は、適切なスレッド同期プリミティブ(Mutex, WaitHandle, Sempahore, ...)をセットアップして、スレッドに直ちに停止を知らせることができます。
残念ながら、Invoke/BeginInvokeの使用のために残念ながらスレッドへの参加は不十分です。 UIスレッドは、検証したとおり、デッドロックの原因となるInvoke/BeginInvoke完了(UIスレッドで実行される)の完了を必要とするワーカースレッドの完了を待機することがあります。 – ceztko
他のスレッドと同期する必要があるため簡単な解決策はありませんが、InvokeはUIスレッドで実行を依頼します。したがって、tUIはt1、t2に終了を依頼しますが、t1、t2はtUIを終了する必要があります。 :)
は、このようなquitting
方法に(すべてがリクエストを呼び出す=プロセスを読む)Application.DoEvents();
の追加:
private void quitting(object sender, FormClosingEventArgs e)
{
start_a = false;
start_b = false;
Application.DoEvents(); // NOT the solution, is not enough!!!
}
ソートほとんどの競合条件が、十分ではありません。
なぜですか?
t1 before queuing Invoke
~~~~~~~>
start_a = false; start_b= false; Application.DoEvents();
<~~~~~~~
t1 queue an Invoke
~~~~~~~> (very improbable but possible)
(continue trough disposing)
<~~~~~~~
queued Invoke on disposed label -> crash!
開始変数の状態をチェックし、トリックを行う必要があり、メッセージキューを空のクリティカルセクションをロック:このための可能な、しかし非常にありえない、競合状態の。あなたのエクササイズ:他の競争条件を見つけ、最悪の場合に5秒より早く終了する方法を見つけます(ヒント:スリープを使用しないでください。スリープは悪魔です)。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
object _closing1;
object _closing2;
volatile bool start_a = false;
volatile bool start_b = false;
public Form1()
{
InitializeComponent();
button1.Text = "Click to start";
button2.Text = "Click to start";
_closing1 = new object();
_closing2 = new object();
}
private void button1_Click(object sender, EventArgs e)
{
if (start_a == false)
{
button1.Text = "Running";
start_a = true;
Thread thread2 = new Thread(new ThreadStart(th1));
thread2.Start();
}
else
{
button1.Text = "Click to start";
start_a = false;
}
}
void th1()
{
int a = 0;
while (true)
{
lock (_closing1)
{
if (start_a == false)
break;
label1.BeginInvoke((MethodInvoker)(() => label1.Text = Convert.ToString(a)));
}
Thread.Sleep(50);
a++;
}
}
void th2()
{
int b = 0;
while (true)
{
lock (_closing2)
{
if (start_b == false)
break;
label2.BeginInvoke((MethodInvoker)(() => label2.Text = Convert.ToString(b)));
}
Thread.Sleep(5000);
b = b + 5;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (start_b == false)
{
button2.Text = "Running";
start_b = true;
Thread thread2 = new Thread(new ThreadStart(th2));
thread2.Start();
}
else
{
button2.Text = "Click to start";
start_b = false;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
lock (_closing1)
{
start_a = false;
// Clear the message queue now so access on disposed lables is possible.
// No more invokes will be queued because 1) start_a = false
// 2) t1 is out of the critical section
Application.DoEvents();
}
lock (_closing2)
{
start_b = false;
// Clear the message queue now so access on disposed lables is possible.
// No more invokes will be queued because 1) start_b = false
// 2) t2 is out of the critical section
Application.DoEvents();
}
}
}
}
- 1. エラー:ウィンドウハンドルが作成されるまで、InvokeまたはBeginInvokeをコントロールで呼び出すことはできません。
- 2. ウィンドウを閉じるときに "InvokeまたはBeginInvokeを呼び出すことができません..."
- 3. フォームを1回だけ閉じることができます。InvalidOperation Exception InvokeまたはBeginInvokeは、ウィンドウハンドルが作成されるまでコントロールで呼び出すことができません。
- 4. スレッドからInvoke/BeginInvokeを呼び出す
- 5. ウィンドウハンドルが作成されていないため、BeginInvokeが失敗します
- 6. コールバック関数内で呼び出されたときdivが作成されたままになりません
- 7. Response.Redirectをページコールバックで呼び出すことはできません
- 8. didReadRSSIはiOSでは呼び出されましたが、OS Xでは呼び出されません
- 9. pygame.Surfaceオブジェクトが呼び出すことはできません
- 10. 'DataFrame'オブジェクトは呼び出すことができません。
- 11. java.lang.RuntimeException:Looper.prepare(呼び出されていないスレッド内でハンドラを作成することはできません)
- 12. エラー:looper.prepareは()を呼び出すことはできません
- 13. 私は現在のクラスの外でコントロールを呼び出すことができますが、操作することはできません
- 14. コードビハインドのブートストラップページのコントロールを呼び出すことができません
- 15. Goでhttp.HandleFuncを呼び出すことができません
- 16. CSHTMLでjavascriptを呼び出すことができません
- 17. コントローラでファクトリを呼び出すことができません
- 18. Android onRequestPermissionsResultがアクティビティでのみ呼び出されましたが、フラグメントでは呼び出されません
- 19. RequestQueueのRequestQueue()を呼び出すことはできません
- 20. オーベルモードライブラリ:#defineを呼び出すことはできません。
- 21. LocationServices.FusedLocationApi.requestLocationUpdatesが呼び出されることはありません
- 22. DeviceAdminReceiverが呼び出されることはありません
- 23. AndroidのcheckLocationSettingsがonResumeで呼び出されたことはありません
- 24. jQuery AJAXはIE8で「エラー:このメソッドはオープンメソッドが呼び出されるまで呼び出すことができません。
- 25. セレクタはnumberOfRowsInSectionで呼び出されますが、cellForRowAtIndexPathでは呼び出されません
- 26. オブジェクト呼び出すことはできませんエラーアクセス配列
- 27. intオブジェクト呼び出すことはできませんエラー
- 28. 「LISTオブジェクト呼び出すことはできませんERROR
- 29. のPython:floatオブジェクト呼び出すことはできません
- 30. WebClient.DownloadStringを呼び出すまでInvoke-WebRequestは機能しません。
あなたの質問がありますか? – bdonlan
フォームを閉じる前にスレッドを停止する必要があります。 –
+1は問題が現実の世界であるためです。しかし次回はどこに問題があるのか正確に指定してください。私はそれを見つけるために自分自身をコンパイルし、テストしなければならなかった。 – ceztko