Обнаружение того, что рабочий элемент ThreadPool завершен/ожидает завершения
-
03-07-2019 - |
Вопрос
Для любой причины, ThreadPool
's QueueWorkItem
не возвращает IAsyncResult
или какой-либо другой дескриптор рабочего элемента, который позволит дождаться его завершения.Есть RegisterWait...
методы, но вам нужно передать WaitHandle
и создавать их дорого (см. IAsyncResult
документации, в которой рекомендуется отложить создание WaitHandle
пока не попросят).Библиотека параллельных задач исправит этот недостаток, но прежде чем она станет доступной, придется долго ждать.Итак, есть ли проблемы с этой конструкцией:
public class Concurrent<T> {
private ManualResetEvent _resetEvent;
private T _result;
public Concurrent(Func<T> f) {
ThreadPool.QueueUserWorkItem(_ => {
_result = f();
if (_resetEvent != null)
_resetEvent.Set();
});
}
public WaitHandle WaitHandle {
get {
if (_resetEvent == null)
_resetEvent = new ManualResetEvent(_result != null);
return _resetEvent;
}
...
РЕДАКТИРОВАТЬ:Я спросил дополнительный вопрос о проблемах, которые возникают при использовании асинхронных делегатов вместо ThreadPool.
Решение
Итак, у вас есть состояние гонки между получением WaitHandle и его установкой.Вы действительно хотите, чтобы звонивший ждал вечно, если он немного опоздает?
Вероятно, вам следует выполнить соответствующую блокировку и сохранить флаг «Я закончил», чтобы, если вы делать создайте WaitHandle после его завершения, вы установите его перед возвратом.
Я бы также лично написал статический фабричный метод, а не просто использовал общедоступный конструктор, или сделал бы его методом «создать и затем явно запустить шаблон.Постановка рабочего элемента в очередь в конструкторе мне кажется странной.
Другие советы
Почему вы не используете асинхронный делегат, как показано здесь:
http://msdn.microsoft.com/en-us/library/h80ttd5f.aspx
Это сделало бы Concurrent устаревшим, не так ли?