terminando automaticamente tópicos não essenciais em C #

votos
3

Eu tenho um objeto em C # no que eu preciso para executar um método em uma base regular. Gostaria que este método a única executado quando outras pessoas estão usando meu objeto, assim que as pessoas parar de usar meu objeto Gostaria que esta operação de fundo para parar.

Então, aqui está um exemplo simples é esse (que está quebrado):

class Fish
{
    public Fish()
    {
        Thread t = new Thread(new ThreadStart(BackgroundWork));     
        t.IsBackground = true;
        t.Start();
    }

    public void BackgroundWork()
    {
        while(true)
        {
            this.Swim(); 
            Thread.Sleep(1000); 
        }
    }


    public void Swim()
    {
         Console.WriteLine(The fish is Swimming); 
    }
}

O problema é que se eu de novo um objeto de peixe em qualquer lugar, ele nunca fica lixo coletado, causar há uma discussão de fundo referência a ele. Aqui está uma versão ilustrada de código quebrado.

public void DoStuff()
{ 
   Fish f = new Fish();
}
// after existing from this method my Fish object keeps on swimming. 

Eu sei que o objeto peixes devem ser descartáveis ​​e eu deveria limpar o fio de descarte, mas eu não tenho controle sobre meus chamadores e não pode garantir Dispose é chamado.

Como faço para contornar este problema e garantir os threads em segundo plano são automaticamente eliminados mesmo que Descarte não é chamado explicitamente?

Publicado 10/12/2008 em 04:36
fonte usuário
Em outras línguas...                            


3 respostas

votos
2

Acho que a solução IDisposable é a correta.

Se os usuários de sua classe não seguir as orientações para a utilização de classes que implementam IDisposable a culpa é deles - e você pode ter certeza de que a documentação menciona explicitamente como a classe deve ser usado.

Outra, muito mais confuso, opção seria um "KeepAlive" campo DateTime que cada método chamado pelo seu cliente vai atualizar. O segmento de trabalho, em seguida, verifica o campo periodicamente e sai se não foi atualizado por um determinado período de tempo. Quando um método é definir o campo da discussão será reiniciado se ele saiu.

Respondeu 10/12/2008 em 04:47
fonte usuário

votos
2

Isto é como eu faria isso:

class Fish3 : IDisposable
{
    Thread t;
    private ManualResetEvent terminate = new ManualResetEvent(false);
    private volatile int disposed = 0;

    public Fish3()
    {
        t = new Thread(new ThreadStart(BackgroundWork));
        t.IsBackground = true;
        t.Start();
    }

    public void BackgroundWork()
    {
        while(!terminate.WaitOne(1000, false))
        {
            Swim();         
        }
    }

    public void Swim()
    {
        Console.WriteLine("The third fish is Swimming");
    }

    public void Dispose()
    {
        if(Interlocked.Exchange(ref disposed, 1) == 0)
        {
            terminate.Set();
            t.Join();
            GC.SuppressFinalize(this);
        }
    }

    ~Fish3()
    {
        if(Interlocked.Exchange(ref disposed, 1) == 0)
        {
            Dispose();
        }
    }
}
Respondeu 10/12/2008 em 05:39
fonte usuário

votos
4

Aqui está a minha proposta de solução para este problema:

class Fish : IDisposable 
{
    class Swimmer
    {
        Thread t; 
        WeakReference fishRef;
        public ManualResetEvent terminate = new ManualResetEvent(false);

        public Swimmer(Fish3 fish)
        {
            this.fishRef = new WeakReference(fish);
            t = new Thread(new ThreadStart(BackgroundWork));    
            t.IsBackground = true;
            t.Start();
        } 

        public void BackgroundWork()
        {
            bool done = false;
            while(!done)
            {
                done = Swim(); 
                if (!done) 
                {
                    done = terminate.WaitOne(1000, false);
                } 
            }
        }

        // this is pulled out into a helper method to ensure 
        // the Fish object is referenced for the minimal amount of time
        private bool Swim()
        {
            bool done;

            Fish fish = Fish; 
            if (fish != null)
            {
                fish.Swim(); 
                done = false;
            }
            else 
            {
                done = true;
            }
            return done;
        }

        public Fish Fish
        {
            get { return fishRef.Target as Fish3; }
        }
    }

    Swimmer swimmer;

    public Fish()
    {
            swimmer = new Swimmer(this);
    }

    public void Swim()
    {
        Console.WriteLine("The third fish is Swimming"); 
    }

    volatile bool disposed = false;

    public void Dispose()
    {
        if (!disposed)
        {
            swimmer.terminate.Set();
            disposed = true;
            GC.SuppressFinalize(this);
        }       
    }

    ~Fish() 
    {
        if(!disposed)
        {
            Dispose();
        }
    }
}
Respondeu 25/08/2009 em 01:56
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more