Я написал пул потоков, как мне уведомить методы, использующие его, о том, что задача выполнена? - PullRequest
2 голосов
/ 21 января 2011

Итак, допустим, у меня есть метод, такой как ThreadPool.QueueTask (Delegate d).

Некоторые из этих делегатов должны возвращать значения, но, поскольку они не могут этого сделать (будучи переданы в качестве делегатов), они должны будут принять значение по ссылке в качестве параметра. Как только задача будет выполнена, это значение будет изменено, поэтому вызывающий метод должен это знать.

По сути, метод, передающий задачу в пул потоков, должен ждать, пока она не будет завершена.

Каков наилучший способ сделать это? Должен ли я просто выполнить Threadpool.QueueTask (Delegate d, EventWaitHandle e) или есть более элегантный способ, который был бы очевиден для людей, незнакомых с подобными вещами?

С уважением, Фуга

Ответы [ 2 ]

5 голосов
/ 21 января 2011

Вы можете использовать ManualResetEvent :

public void TaskStartMethod()
{
    ManualResetEvent waitHandle = new ManualResetEvent(false);

    ThreadPool.QueueUserWorkItem(o=>
    {
        // Perform the task here

        // Signal when done
        waitHandle.Signal();
    });

    // Wait until the task is complete
    waitHandle.WaitOne();
}

По сути, метод, передающий задачу в пул потоков, должен ждать, пока она не будет завершена.

Приведенный выше код делает это, но теперь у меня есть вопрос: если ваш метод ожидает завершения задачи, то зачем вам вообще выполнять задачу в отдельном потоке?Другими словами, вы описываете последовательное выполнение кода, а не параллельное, поэтому использование ThradPool бессмысленно.

С другой стороны, вы можете использовать отдельный делегат в качестве обратного вызова:

public delegate void OnTaskCompleteDelegate(Result someResult);

public void TaskStartMethod()
{
    OnTaskCompleteDelegate callback = new OnTaskCompleteDelegate(OnTaskComplete);
    ThradPool.QueueUserWorkItem(o=>
    {
        // Perform the task

        // Use the callback to notify that the
        // task is complete. You can send a result
        // or whatever you find necessary.
        callback(new Result(...));
    });

}

public void OnTaskComplete(Result someResult)
{
    // Process the result
}

Обновление (24.01.2011): Возможно, вам даже не понадобится делегат обратного вызова, вы можете просто напрямую позвонить OnTaskComplete, и это тоже должно сделать эту работу:

public void TaskStartMethod()
{
    ThradPool.QueueUserWorkItem(o=>
    {
        // Perform the task

        // Call the method when the task is complete
        OnTaskComplete(new Result(...));
    });
}
1 голос
/ 21 января 2011

Зависит от того, как вы это делаете.Для меня это звучит немного похоже на то, что у вас есть поток А, который помещает одну задачу в пул потоков, а затем ждет ее завершения.Это звучит не очень полезно.Если вы помещаете одну задачу в пул потоков и ожидаете, просто сделайте это в своем собственном потоке.

Но это, вероятно, не то, что вы делаете!

Я вижу два возможных хороших способа использования пула потоков.В потоке A есть несколько вещей, которые он хочет запустить параллельно, а затем дождаться их завершения.В этом случае вам нужно сохранить дескриптор для всех задач (или класса результатов), чтобы вы могли дождаться их завершения.Вы можете использовать полуфоры или различные инструменты синхронизации (особенно я не делаю на c #), чтобы избежать необходимости проводить опрос.

Другой способ - использовать обратный вызов в конце задачи.Поток A запускает задачу в пуле потоков и затем существует.Задача имеет дескриптор класса, который ее инициировал, и вызывает функцию типа обратного вызова, когда она завершена, чтобы выполнить тип финализации.

...