Pergunta

Eu tenho uma classe BackgroundWorker nomeado que tem uma rosca funcionando constantemente. Para desligar essa linha, uma variável de instância nomeada stop às necessidades para ser true.

Para certificar-se o fio é liberado quando a classe é feito sendo usado, eu adicionei IDisposable e um finalizador que chama Dispose(). Assumindo que stop = true faz de fato causa esta discussão para sair, é este bocado de pão torrado correto? É bom para Dispose invocação de um finalizador, certo?

Os finalizadores deve sempre chamar Dispose se as herda object IDisposable, certo?

/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
    lock (this.locker)
    {
        this.stop = true;
    }
}

~BackgroundWorker()
{
    this.Dispose();
}
Foi útil?

Solução

Seu código é bom, embora o bloqueio em um finalizador é um pouco "assustador" e eu gostaria de evitá-lo - se você receber um impasse ... Eu não estou 100% certo o que iria acontecer, mas não seria bom. No entanto, se você está seguro isso não deve ser um problema. Na maioria das vezes. Os internos de coleta de lixo são dolorosas e eu espero que você nunca tem que vê-los;)

Como aponta Marc Gravell, um bool volátil permitiria que você se livrar do bloqueio, que iria minimizar o problema. Implementar esta alteração, se puder.

O nedruod puts código a atribuição dentro da seleção se (eliminação), que é completamente errado - o fio é um recurso não gerenciado e deve ser parado, mesmo se não descartar explicitamente. Seu código é bom, estou apenas apontando que você não deve tomar o conselho dado nesse trecho de código.

Sim, você quase sempre deve chamar Dispose () do finalizador se implementar o padrão IDisposable. O padrão IDisposable completo é um pouco maior do que o que você tem, mas nem sempre você precisa dele - fornece apenas duas possibilidades extras:

  1. detectar se Dispose () foi chamado ou o finalizador está executando (você não estão autorizados a tocar quaisquer recursos gerenciados no finalizador, fora do objeto que está sendo finalizado);
  2. permitindo subclasses para substituir o método Dispose ().

Outras dicas

Primeiro, a severa advertência . Não use um finalizador como você é. Você está se preparando para alguns efeitos muito ruins se você tomar fechaduras dentro de um finalizador. história curta é não fazê-lo. Agora à pergunta inicial.

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

/// <summary>
/// Force the background thread to exit.
/// </summary>
protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this.locker)
        {
            this.stop = true;
        }
    }
}

~BackgroundWorker()
{
    Dispose(false);
}

A única razão para ter um finalizador em tudo é permitir sub-classes de estender e solte recursos não gerenciados . Se você não tem subclasses, em seguida, selar sua classe e soltar o finalizador completamente.

Fora de interesse, qualquer razão isso não poderia usar o regulares BackgroundWorker , que tem suporte completo para cancelamento?

Re o bloqueio -. Um campo bool volátil pode ser menos problemático

No entanto, neste caso o seu finalizador não está fazendo nada interessante, especialmente tendo em conta o "se (eliminação)" - ou seja, ele só é executado o código interessante durante Dispose (). Pessoalmente eu estaria tentado a ficar com apenas IDisposable, e não fornecer um finalizador:. Você deve limpá-lo com Dispose ()

É o "stop" variável de instância uma propriedade? Se não, não há nenhum ponto em particular no estabelecimento durante o finalizador -. Nada está referenciando o objeto mais, então nada pode consultar o membro

Se você está realmente lançando um recurso, em seguida, ter Dispose () eo finalizador executar o mesmo trabalho (primeiro testar se o trabalho ainda precisa ser feito) é um padrão bom.

Você precisa do padrão descartável completo, mas a parada tem que ser algo que o thread pode acessar. Se é uma variável de membro da classe que está sendo descartado, isso não é bom porque não pode fazer referência a uma classe descartado. Considere ter um evento que o segmento possui e sinalizando que em dispor vez.

O objeto que implementa o finalizador necessita de uma referência a uma bandeira - armazenados em outro objeto - que o segmento será capaz de ver; o mosto fio não tem qualquer referência forte, direta ou indireta, para o objeto que implementa o finalizador. O finalizador deve definir o sinalizador usando algo como um CompareExchange, ea linha deverá utilizar um meio semelhantes para testá-lo. Note que se o finalizador de um objeto acessa outro objeto, o outro objeto pode ter sido finalizado, mas ainda vai existir. É bom para um finalizador para fazer referência a outros objetos, se ele faz isso de uma maneira que não será incomodado pela sua finalização. Se tudo que você está fazendo é definindo um sinalizador, você está bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top