每次返回ThreadPool.QueueUserWorkItem方法时如何调用完成方法

时间:2012-03-29 17:01:16

标签: c# multithreading threadpool

我正在使用

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

我希望每次调用MyMethod时都从主线程调用以下方法:

UpdateGui()
{

}

我该怎么做?

谢谢!

4 个答案:

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