Автоматическое прекращение неосновных потоков в C #

голоса
3

У меня есть объект в C #, на котором мне нужно выполнить метод на регулярной основе. Я хотел бы этот метод будет выполняться только тогда, когда другие люди используют свой объект, как только люди прекратить использование моего объекта, я хотел бы это фоновая операция, чтобы остановить.

Так вот простой пример этого (который не работает):

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); 
    }
}

Проблема заключается в том, что если я новый объект рыбы в любом месте, он никогда не будет мусора, причина есть фоновый поток на него ссылаются. Вот иллюстрированная версия разбитого кода.

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

Я знаю, что объект Рыба должна быть одноразовыми и я должен очистить резьбу на распоряжаются, но я не имею никакого контроля над своими абонентами и не может обеспечить отчуждать называется.

Как решить эту проблему и обеспечить фоновые потоки автоматически уничтожаются даже если Dispose не вызывается явно?

Задан 10/12/2008 в 04:36
источник пользователем
На других языках...                            


3 ответов

голоса
4

Здесь предложено мое решение этой проблемы:

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();
        }
    }
}
Ответил 25/08/2009 в 01:56
источник пользователем

голоса
2

Это, как я хотел бы сделать это:

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();
        }
    }
}
Ответил 10/12/2008 в 05:39
источник пользователем

голоса
2

Я думаю, что решение IDisposable является правильным.

Если пользователи вашего класса не следовать рекомендациям по использованию классов, реализующих IDisposable это их вина - и вы можете убедиться в том, что документация явно упоминает, как следует использовать класс.

Другой, гораздо грязнее, вариант был бы «KeepAlive» DateTime поля, что каждый метод вызывается вашим клиентом будет обновлять. Рабочий поток затем проверяет поле периодически и выходит, если она не была обновлена ​​в течение определенного периода времени. Когда метод установки поля нить будет перезапущен, если он вышел.

Ответил 10/12/2008 в 04:47
источник пользователем

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