2012-03-29 10 views
0

を返された私は、メインスレッドからMyMethodはへの呼び出しが完了するたびに、次のメソッドを呼び出したい完了メソッド毎回呼び出す方法ThreadPool.QueueUserWorkItemメソッドが

System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5)); 

を使用しています:

UpdateGui() 
{ 

} 

どうすればよいですか?

ありがとうございます!

+1

「MyMethod」内から「Control.Invoke」を呼び出して、デリゲートの実行をUIスレッドにマーシャリングします。 –

+1

なぜ「タスク」とその継続を使用しないのですか? –

+0

@BrianRasmussen:はい、さらに良い! –

答えて

4

作業項目のグローバルカウンタを保つには、それを保護することを目的としキューに入れられ、:

int runningTasks = 0; 
object locker = new object(); 

タスクはカウンタをインクリメント追加されるたびに:

lock(locker) runningTasks++; 
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5)); 

MyMethod減少の終わりにカウンタと信号をメインスレッド:

lock(locker) 
{ 
    runningTasks--; 
    Monitor.Pulse(locker); 
} 

メインスレッド(これはGUIスレッドではないと仮定します)。

lock(locker) 
{ 
    while(runningTasks > 0) 
    { 
     Monitor.Wait(locker);    
     UpdateGUI(); 
    } 
} 

このようにして、保留中のすべてのタスクが完了するのを待つこともできます。

待つ必要がない場合は、MyMethodが終了したら、メインスレッドを完全にスキップして、UpdateGUIを呼び出して更新をGUIスレッドに転送してください。内部MyMethodあなたがそうでなければ、あなたが安全にGUIを更新することはできませんDispatcher.BeginInvoke(WPF)またはControl.BeginInvoke(リサイズ)のいくつかのフォームを持っている必要があり

注意

+0

わかりません。 *ロッカー*はSystem.Objectです、そうですか? System.Objectの.Pulseおよび.Wait拡張メソッドですか? whileループの周りのロックは、永遠にMyMethodの終わりにロックとデクリメントをブロックしませんか? – KristoferA

+0

@ KristoferA-Huagati.com:いいえ、 'Monitor.Wait(locker)'を 'lock(locker)'の中で呼び出すと、他のスレッドがロックを取得できるように自動的にロックが解除されます。また、 'Pulse'と' Wait'は 'Monitor'クラスの静的メソッドであり、' object'の拡張ではありません。 – Tudor

+0

ああ、クール。私はそれを分かってくれたことを知らなかった。 – KristoferA

0

MyMethodそれは非同期に実行させるためにQueueUserWorkItem内部呼び出さ、同期方式であると仮定すると、以下のアプローチを使用することができる:もしによってUpdateGui()内部GUI要素を更新する必要が

ThreadPool.QueueUserWorkItem(x => 
{ 
    MyMethod(param1, param2, param3, param4, param5); 
    UpdateGui(); 
}); 

Invoke/BeginInvokeを呼び出します。

2

ポストをバックスレッドプールメソッドの最後に、UIスレッドの同期コンテキストにupdateguiメソッドの呼び出し...

例:

private SynchronizationContext _syncContext = null; 

public Form1() 
{ 
    InitializeComponent(); 

    //get hold of the sync context 
    _syncContext = SynchronizationContext.Current; 
} 

private void Form1_Load(object sender, EventArgs e) 
{ 
    //queue a call to MyMethod on a threadpool thread 
    ThreadPool.QueueUserWorkItem(x => MyMethod()); 
} 

private void MyMethod() 
{ 
    //do work... 

    //before exiting, call UpdateGui on the gui thread 
    _syncContext.Post(
     new SendOrPostCallback(
      delegate(object state) 
      { 
       UpdateGui(); 
      }), null); 
} 

private void UpdateGui() 
{ 
    MessageBox.Show("hello from the GUI thread"); 
} 
+0

私は理解していません。私にコードを教えてもらえますか?ありがとう、 – Barka

+0

ok、コードサンプルで更新... – KristoferA

0

これせるクライアントクリーナーを保つことクラスはクロススレッドスイッチング機構を処理します。このようにして、GUIは通常の方法でクラスを使用します。

public partial class Form1 : Form 
{ 
    private ExampleController.MyController controller; 
    public Form1() 
    {   
     InitializeComponent(); 
     controller = new ExampleController.MyController((ISynchronizeInvoke) this); 
     controller.Finished += controller_Finished; 

    } 
    void controller_Finished(string returnValue) 
    { 
     label1.Text = returnValue; 
    } 
    private void button1_Click(object sender, EventArgs e) 
    { 
     controller.SubmitTask("Do It"); 
    } 
} 

GUIフォームは、マルチスレッドであることを認識しないクラスのイベントにサブスクライブします。

public class MyController 
{ 
    private ISynchronizeInvoke _syn; 
    public MyController(ISynchronizeInvoke syn) { _syn = syn; } 
    public event FinishedTasksHandler Finished; 
    public void SubmitTask(string someValue) 
    { 
     System.Threading.ThreadPool.QueueUserWorkItem(state => submitTask(someValue)); 
    } 

    private void submitTask(string someValue) 
    { 
     someValue = someValue + " " + DateTime.Now.ToString(); 
     System.Threading.Thread.Sleep(5000); 
//Finished(someValue); This causes cross threading error if called like this. 

     if (Finished != null) 
     { 
      if (_syn.InvokeRequired) 
      { 
       _syn.Invoke(Finished, new object[] { someValue }); 
      } 
      else 
      { 
       Finished(someValue); 
      } 
     } 
    } 
} 
関連する問題