How to call a completion method everytime ThreadPool.QueueUserWorkItem method is returned

帅比萌擦擦* 提交于 2020-01-24 00:55:06

问题


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:

UpdateGui()
{

}

How do I do that?

Thanks!


回答1:


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:

lock(locker) 
{
    runningTasks--;
    Monitor.Pulse(locker);
}

In the main thread (assuming this is not the GUI thread!):

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.

Note that inside MyMethod you should have some form of Dispatcher.BeginInvoke (WPF) or Control.BeginInvoke (WinForms) otherwise you cannot update the GUI safely!




回答2:


Post a call to the updategui method back to the sync context for the ui thread at the end of the threadpool method...

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



回答3:


Assuming that MyMethod is a synchronous method, invoked inside QueueUserWorkItem in order to make it execute asynchronously, the following approach may be used:

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

Note that you have to update GUI elements inside UpdateGui() by calling Invoke/BeginInvoke.




回答4:


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.

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.

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


来源:https://stackoverflow.com/questions/9930007/how-to-call-a-completion-method-everytime-threadpool-queueuserworkitem-method-is

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!