我正在使用
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
我希望每次调用MyMethod时都从主线程调用以下方法:
UpdateGui()
{
}
我该怎么做?
谢谢!
答案 0 :(得分: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();
}
}
通过这种方式,您还可以等待所有待处理的任务完成。
如果您不想等待,只需完全跳过主线程,并在UpdateGUI
完成时调用MyMethod
将更新转发到GUI线程。
注意在MyMethod
内你应该有某种形式的Dispatcher.BeginInvoke
(WPF)或Control.BeginInvoke
(WinForms),否则你无法安全地更新GUI! / p>
答案 1 :(得分:2)
在threadpool方法结束时将对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");
}
答案 2 :(得分:0)
假设MyMethod
是一个同步方法,在QueueUserWorkItem
内调用以使其异步执行,可以使用以下方法:
ThreadPool.QueueUserWorkItem(x =>
{
MyMethod(param1, param2, param3, param4, param5);
UpdateGui();
});
注意您必须通过调用UpdateGui()
/ Invoke
来更新BeginInvoke
中的GUI元素。
答案 3 :(得分: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);
}
}
}
}