Pergunta

A implementação abaixo thread-safe? Se não o que eu estou ausente? Devo ter a algum lugar palavras-chave volatile? Ou em algum lugar de bloqueio no método OnProcessingCompleted? Se sim, onde?

public abstract class ProcessBase : IProcess
{
    private readonly object completedEventLock = new object();

    private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted;

    event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted
    {
        add
        {
            lock (completedEventLock)
                ProcessCompleted += value;
        }
        remove
        {
            lock (completedEventLock)
                ProcessCompleted -= value;
        }
    }

    protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
    {
        EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted;
        if (handler != null)
            handler(this, e);
    }
}

Nota: A razão pela qual eu tenho evento privado e material de interface explícita, é porque é uma classe base abstrata. E as classes que herdam dele não deve fazer nada com esse evento diretamente. Adicionado o wrapper classe para que ele é = mais claras)

Foi útil?

Solução

Não há necessidade do membro ProcessCompleted privada para ser um event - que poderia ser apenas um campo:. private EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - dentro da classe que sempre vai direto para o campo, de modo que o material event é perdido de qualquer maneira

A abordagem que você mostrou com um objeto de bloqueio explícito não é muito mais thread-safe do que apenas ter um campo-like evento (ie public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - a única diferença é que você não está bloqueio "isto" (que é uma coisa boa - você deve idealmente bloqueio evitar nas this) .. a abordagem "variável manipulador" é o caminho certo, mas ainda há

Outras dicas

Você precisa bloquear quando você buscar o manipulador também, caso contrário você não pode ter o valor mais recente:

protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
    EventHandler<ProcessCompletedEventArgs> handler;
    lock (completedEventLock) 
    {
        handler = ProcessCompleted;
    }
    if (handler != null)
        handler(this, e);
}

Note que esta não prevenir uma condição de corrida onde nós decidimos que vamos executar um conjunto de manipuladores e então um manipulador não subscritas. Ele ainda vai ser chamado, porque temos buscado o delegado multicast contendo-o na variável handler.

Não há muita coisa que você pode fazer sobre isso, além de fazer o manipulador própria consciência de que não deve ser chamado mais.

É, sem dúvida, melhor apenas não tente para fazer os eventos thread-safe - especificar que a assinatura deve única mudança na discussão que irá aumentar o evento

scroll top