简体   繁体   English

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

[英]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.

相关问题 ThreadPool.QueueUserWorkItem,带有lambda表达式和匿名方法 - ThreadPool.QueueUserWorkItem with a lambda expression and anonymous method 在 ThreadPool.QueueUserWorkItem() 方法中启动时 DispatcherTimer 滴答不工作 - DispatcherTimer ticking not working when started in ThreadPool.QueueUserWorkItem() method ThreadPool.QueueUserWorkItem与线程内的异步调用 - ThreadPool.QueueUserWorkItem with Async Call within the thread "如何从 ThreadPool.QueueUserWorkItem 中捕获异常?" - How to catch exceptions from a ThreadPool.QueueUserWorkItem? 如何中止使用ThreadPool.QueueUserWorkItem创建的线程 - How to abort threads created with ThreadPool.QueueUserWorkItem ThreadPool.QueueUserWorkItem中的AgrumenNullException - AgrumenNullException in ThreadPool.QueueUserWorkItem ThreadPool.QueueUserWorkItem NullReferenceException - ThreadPool.QueueUserWorkItem NullReferenceException ThreadPool.QueueUserWorkItem在c#2.0中的单独线程中运行方法时出错 - ThreadPool.QueueUserWorkItem Error when run method in separate thread in c# 2.0 ThreadPool.QueueUserWorkItem preferredLocal是做什么的? - What is ThreadPool.QueueUserWorkItem preferLocal for? 带有函数参数的 ThreadPool.QueueUserWorkItem - ThreadPool.QueueUserWorkItem with function argument
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM