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

C# 如何在每次返回ThreadPool.QueueUserWorkItem方法时调用完成方法,c#,multithreading,threadpool,C#,Multithreading,Threadpool,我正在使用 System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5)); 每次调用MyMethod完成时,我都希望从主线程调用以下方法: UpdateGui() { } 我该怎么做 谢谢 将工作项的全局计数器保持在队列中,并使用一个对象对其进行保护: int runningTasks = 0; object locker = new objec

我正在使用

System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
每次调用MyMethod完成时,我都希望从主线程调用以下方法:

UpdateGui()
{

}
我该怎么做


谢谢

将工作项的全局计数器保持在队列中,并使用一个对象对其进行保护:

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线程!):

这样,您也有一个障碍,等待所有挂起的任务完成

如果您不想等待,只需完全跳过主线程,并在
MyMethod
完成时调用
UpdateGUI
将更新转发到GUI线程


注意
MyMethod
中,您应该具有某种形式的
调度程序.BeginInvoke
(WPF)或
控件.BeginInvoke
(WinForms),否则您无法安全地更新GUI

将工作项的全局计数器保持在队列中,并使用一个对象对其进行保护:

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线程!):

这样,您也有一个障碍,等待所有挂起的任务完成

如果您不想等待,只需完全跳过主线程,并在
MyMethod
完成时调用
UpdateGUI
将更新转发到GUI线程


注意
MyMethod
中,您应该具有某种形式的
调度程序.BeginInvoke
(WPF)或
控件.BeginInvoke
(WinForms),否则您无法安全地更新GUI

假设
MyMethod
是一个同步方法,在
QueueUserWorkItem
内部调用,以使其异步执行,可以使用以下方法:

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

注意您必须通过调用
Invoke
/
BeginInvoke

来更新
UpdateGui()中的GUI元素,假设
MyMethod
是一个同步方法,在
QueueUserWorkItem
内部调用,以使其异步执行,可以使用以下方法:

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

注意您必须通过调用
Invoke
/
BeginInvoke

将对UpdateGui方法的调用发回线程池方法末尾的ui线程的同步上下文来更新
UpdateGui()
中的GUI元素

例如:

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

将对updategui方法的调用发回threadpool方法末尾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");
}

这可以使客户端更干净,让类处理跨线程切换机制。通过这种方式,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);
            }
        }
    }
}

这可以使客户端更干净,让类处理跨线程切换机制。通过这种方式,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);
            }
        }
    }
}

调用
Control。从
MyMethod
中调用
,将委托的执行封送到UI线程。为什么不使用
Task
和continuations呢?@BrianRasmussen:是的,甚至更好@BrianRasmussen,UpdateGui有死锁问题,我不明白,所以我想在主线程上运行它。使用ContinueWith启动一个新任务,死锁问题仍然存在。我只想在Spin thread方法返回后在主线程上调用一个方法。@user277498:您可以指定启动任务/continuations时要使用的同步上下文。调用
Control。从
MyMethod
中调用
,将委托的执行封送到UI线程上。为什么不使用
Task
“那还要继续吗?”布莱恩拉斯穆森:是的,甚至更好@BrianRasmussen,UpdateGui有死锁问题,我不明白,所以我想在主线程上运行它。使用ContinueWith启动一个新任务,死锁问题仍然存在。我只想在Spin thread方法返回后在主线程上调用一个方法。@user277498:您可以指定启动任务/继续时要使用的同步上下文。我不明白。储物柜是一个系统,物体,对吗?是System.Object的.Pulse和.Wait扩展方法吗?而while循环周围的锁,不会永远阻止MyMethod末尾的锁和减量吗?@KristoferA-Huagati.com:不会,当你调用
Monitor.Wait(locker)
lock(locker)
中时,锁会自动释放,以允许其他线程获取锁。另外,
Pulse
Wait
是类
Monitor
的静态方法,而不是
对象的扩展。我不明白。储物柜是一个系统,物体,对吗?是System.Object的.Pulse和.Wait扩展方法吗?而while循环周围的锁,不会永远阻止MyMethod末尾的锁和减量吗?@KristoferA-Huagati.com:不会,当你调用
Monitor.Wait(locker)
lock(locker)
中时,锁会自动释放,以允许其他线程获取锁。另外,
Pulse
Wait
是类
监视器的静态方法,而不是
对象的扩展。