2012-03-29 34 views
0

ThreadPool.QueueUserWorkItem方法,我用如何調用完成方法每次返回

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

我希望每次調用的MyMethod完成時調用從主線程下面的方法:

UpdateGui() 
{ 

} 

我該怎麼做?

謝謝!

+1

調用'MyMethod'內的'Control.Invoke'來將委託的執行編組到UI線程中。 – 2012-03-29 17:06:15

+1

爲什麼不使用'Task'和延續? – 2012-03-29 17:15:47

+0

@BrianRasmussen:是的,甚至更好! – 2012-03-29 17:16:45

回答

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你應該有某種形式的Dispatcher.BeginInvoke(WPF)或Control.BeginInvoke(的WinForms),否則你不能安全地更新GUI!

+0

我不明白。 * locker *是一個System.Object,對嗎?是.Pulse和.Wait System.Object的擴展方法?圍繞while循環的鎖定不會阻止MyMethod結束時的鎖定和遞減嗎? – KristoferA 2012-03-31 05:46:28

+0

@ KristoferA-Huagati.com:不,當你在鎖(locker)內調用'Monitor.Wait(locker)'時,鎖會自動釋放,以允許其他線程獲得鎖。此外,'Pulse'和'Wait'是類Monitor的靜態方法,不是'object'的擴展。 – Tudor 2012-03-31 06:47:57

+0

哦,很酷。我不知道,謝謝澄清。 – KristoferA 2012-03-31 12:30:30

0

假設MyMethod是一個同步方法中,爲了內QueueUserWorkItem調用,以使其異步執行,以下方法可以用來:

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

注意,你必須通過更新內部UpdateGui() GUI元素呼籲Invoke/BeginInvoke

2

張貼到updategui方法回在線程池方法結束UI線程同步情境中的呼叫......

例子:

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 2012-03-29 17:34:25

+0

好的,用代碼示例更新... – KristoferA 2012-03-30 00:52:28

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); 
      } 
     } 
    } 
}