Если вы действительно хотите выделить один поток для каждой задачи, тогда нет необходимости вообще использовать WaitHandle
экземпляров. 1 Вы можете передать экземпляр Thread
, который выполняет родительскую задачу, к каждой дочерней задаче и вызовите Join
, чтобы убедиться, что родительская задача завершена.
void TaskEntryPoint(Thread parent, ImportTask task)
{
if (parent != null)
{
parent.Join(); // Wait for the parent task to complete.
}
task.Execute(); // Execute the child task.
}
Теперь все, что вам нужно сделать, это запустить родительские задачи в их собственных отдельных потоках, а затем получить дочернюю.Задачи собираются своими собственными отдельными потоками.При вызове TaskEntryPoint
передайте null
, если это для родительской задачи, и передайте соответствующий экземпляр Thread
для каждой дочерней задачи.
Обновление:
На основеВ вашем комментарии приведен пример того, как я могу подойти к проблеме, используя ThreadPool
.Это довольно сложный шаблон, использующий метод ThreadPool.RegisterWaitForSingleObject
.Это также оказывается чрезвычайно масштабируемым решением, поскольку оно использует абсолютный минимум ресурсов для ожидания сигнала WaitHandle
.
foreach (ImportTask parent in parentTasks)
{
// This WaitHandle will be used to get the child tasks going.
var wh = new ManualResetEvent(false);
// Needed to capture the loop variable correctly.
var p = parent;
// Queue the parent task.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
// Execute the parent task.
p.Execute();
}
finally
{
// Signal the event so that the child tasks can begin executing.
wh.Set();
}
}, null);
// Register the child tasks.
foreach (ImportTask child in parent.ChildTasks)
{
// Needed to capture the loop variable correctly.
var c = child;
// Registers a callback for the child task that will execute once the
// parent task is complete.
RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(wh,
(state, to) =>
{
// Execute the child task.
c.Execute();
},
null, Timeout.Infinite, true);
}
}
Волшебство здесь в том, как RegisterWaitForSingleObject
ожидаетсобытие.Он зарегистрирует обратный вызов, который будет автоматически выполнен, как только событие будет сообщено.Но он делает это таким образом, что ни один поток в пуле не тратится впустую на ожидание этого события.Опять же, это довольно сложный шаблон, который потребует некоторых размышлений с вашей стороны, но он будет очень масштабируемым.
1 Запуск нового потока длякаждая задача не может быть лучшей стратегией.Рассматривали ли вы использование ThreadPool
или Task
классов?