Detectar que um ThreadPool WorkItem completou / à espera de conclusão
-
03-07-2019 - |
Pergunta
Por alguma razão, ThreadPool
de QueueWorkItem
não retorna um IAsyncResult
ou algum outro identificador para o item de trabalho, o que permitiria que esperar até que seja concluída. Existem métodos RegisterWait...
, mas você tem que passar por um WaitHandle
e criá-los é caro (consulte a documentação IAsyncResult
, que aconselha a atrasar a criação de um WaitHandle
até solicitado). A biblioteca paralela de tarefas irá corrigir essa falta, mas há uma longa espera antes que está disponível. Então, existem problemas com este projeto:
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;
}
...
EDIT: Perguntei a um follow-up questão sobre as preocupações que surgem quando se utiliza delegados assíncronos em vez do ThreadPool .
Solução
Bem, você tem uma condição de corrida entre buscar o WaitHandle e defini-lo. Você realmente quer o chamador para ser esperando para sempre, se acontecer de ser um pouco tarde?
Você provavelmente deve fazer algum bloqueio apropriado e manter uma bandeira "Eu terminei", de modo que se você do criar o WaitHandle depois que terminar, você configurá-lo antes de devolvê-lo.
Eu também, pessoalmente, escrever um método de fábrica estático em vez de apenas usando um construtor público - ou torná-lo um "criar e então explicitamente iniciar" padrão. Enfileiramento o item de trabalho no construtor sente estranho para mim.
Outras dicas
Por que você não está usando um delegado assíncrona, como demostrated aqui:
http://msdn.microsoft.com/en-us/library /h80ttd5f.aspx
Isso faria Concurrent obsoleto, não?