[英]How to call a completion method everytime ThreadPool.QueueUserWorkItem method is returned
I am using 我在用
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
I want to call the following method from the main thread every time the call to MyMethod is completed: 我想在每次对MyMethod的调用完成时从主线程调用以下方法:
UpdateGui()
{
}
How do I do that? 我怎么做?
Thanks! 谢谢!
Keep a global counter of work items queued and an object to protect it: 将工作项的全局计数器排在队列中,并设置一个对象来保护它:
int runningTasks = 0;
object locker = new object();
Every time a task is added increment the counter: 每次添加任务时,计数器都会递增:
lock(locker) runningTasks++;
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
At the end of MyMethod
decrement the counter and signal the main thread: 在
MyMethod
的末尾递减计数器并向主线程发送信号:
lock(locker)
{
runningTasks--;
Monitor.Pulse(locker);
}
In the main thread (assuming this is not the GUI thread!): 在主线程中(假设这不是GUI线程!):
lock(locker)
{
while(runningTasks > 0)
{
Monitor.Wait(locker);
UpdateGUI();
}
}
This way you also have a barrier to wait for all pending tasks to finish. 这样,您也有等待所有待处理任务完成的障碍。
In case you don't want to wait, just skip the main thread completely and call UpdateGUI
to forward updates to the GUI thread when MyMethod
finishes. 万一您不想等待,只需完全跳过主线程并在
MyMethod
完成时调用UpdateGUI
将更新转发到GUI线程即可。
Note that inside MyMethod
you should have some form of Dispatcher.BeginInvoke
(WPF) or Control.BeginInvoke
(WinForms) otherwise you cannot update the GUI safely! 请注意 ,在
MyMethod
内部,您应该具有某种形式的Dispatcher.BeginInvoke
(WPF)或Control.BeginInvoke
(WinForms),否则您将无法安全地更新GUI!
Post a call to the updategui method back to the sync context for the ui thread at the end of the threadpool method... 在线程池方法的末尾将对updategui方法的调用发回到ui线程的同步上下文中...
Example: 例:
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");
}
This may keep the client cleaner letting the class handle the cross threading switching mechanism. 这可以使客户端保持整洁,让类处理跨线程切换机制。 This way the GUI consumes your class in normal fashion.
这样,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");
}
}
The GUI form subscribes to events of the class unaware they are mulch-threaded. 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);
}
}
}
}
Assuming that MyMethod
is a synchronous method, invoked inside QueueUserWorkItem
in order to make it execute asynchronously, the following approach may be used: 假设
MyMethod
是一个同步方法,在QueueUserWorkItem
内部调用以使其异步执行,则可以使用以下方法:
ThreadPool.QueueUserWorkItem(x =>
{
MyMethod(param1, param2, param3, param4, param5);
UpdateGui();
});
Note that you have to update GUI elements inside UpdateGui()
by calling Invoke
/ BeginInvoke
. 请注意 ,您必须通过调用
Invoke
/ BeginInvoke
来更新UpdateGui()
的GUI元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.