简体   繁体   中英

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:

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:

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!

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

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

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM