Как вызывать метод завершения каждый раз, когда возвращается метод ThreadPool.QueueUserWorkItem - PullRequest
0 голосов
/ 29 марта 2012

Я использую

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

Я хочу вызывать следующий метод из основного потока каждый раз, когда завершается вызов MyMethod:

UpdateGui()
{

}

Как мне это сделать?

Спасибо!

Ответы [ 4 ]

4 голосов
/ 29 марта 2012

Сохранить глобальный счетчик рабочих элементов в очереди и объект для его защиты:

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 для пересылки обновлений в поток GUI после завершения MyMethod.

Обратите внимание , что внутри MyMethod у вас должна быть какая-то форма Dispatcher.BeginInvoke (WPF) или Control.BeginInvoke (WinForms), в противном случае вы не сможете безопасно обновлять графический интерфейс!

2 голосов
/ 29 марта 2012

Опубликовать вызов метода updategui обратно в контекст синхронизации для потока пользовательского интерфейса в конце метода пула потоков ...

Пример:

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");
}
0 голосов
/ 11 сентября 2013

Это может обеспечить чистоту клиента, позволяя классу управлять механизмом переключения между потоками.Таким образом, графический интерфейс потребляет ваш класс обычным способом.

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 подписывается на события класса, не подозревая, что они являются многопоточными.

0 голосов
/ 29 марта 2012

Предполагая, что MyMethod является синхронным методом, вызываемым внутри QueueUserWorkItem, чтобы заставить его выполняться асинхронно, может использоваться следующий подход:

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

Обратите внимание , что вам нужно обновить элементы GUI внутри UpdateGui(), вызвав Invoke / BeginInvoke.

...