是否可以从拥有对象的Dispose方法中停止线程?

本文关键字:方法 线程 Dispose 拥有 对象 是否 | 更新日期: 2023-09-27 18:02:20

下面是一个简单的例子:

class MyClass : IDisposable
{
    bool working;
    public MyClass()
    {
        working = true;
        Thread t = new Thread(Worker);
        t.Start();
    }
    void Worker()
    {
        while(working)
        {}
    }
    public void Dispose()
    {
        working = false;
    }
}

这样做可以吗?Dispose()会在线程还在运行的时候被调用吗?如果没有,如何更好地做到这一点?

是否可以从拥有对象的Dispose方法中停止线程?

Dispose将不会被调用,除非你显式地调用它,或者通过在using语句中包含MyClass实例化。

将处置()甚至被调用,而线程仍在运行?

可以这样调用:

using (MyClass m = new MyClass())
{
    System.Threading.Thread.Sleep(2000);
}

因此,一旦using块结束,它将调用类中的Dispose方法。

(尽管您的变量应该是volatile,以表明该字段可能被多个线程修改)

但重要的是要注意,Dispose没有什么神奇的东西,甚至using语句也转换成try-finally,其中Disposefinally块中显式调用。

你不应该依赖于你的Dispose方法将被调用。

你可以用WeakReference包装你的类实例。一旦引用被垃圾收集,线程应该停止它的工作。

class MyClass : IDisposable
{
    class CancellationSignal
    {
        WeakReference _reference;
        public bool IsWorking { get { return _working && _reference.IsAlive; } }
        volatile bool _working;
        public CancellationSignal(WeakReference reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            _reference = reference;
        }
        public void Signal()
        {
            _working = false;
        }
    }
    CancellationSignal _cancellationSignal;
    public MyClass()
    {
        _cancellationSignal = new CancellationSignal(new WeakReference(this));
        Thread t = new Thread(Worker);
        t.Start(_cancellationSignal);
    }
    static void Worker(object state)
    {
        var s = (CancellationSignal)state;
        while (s.IsWorking)
        {
            //...
        }
    }
    public void Dispose()
    {
        _cancellationSignal.Signal();
    }
}

我个人更喜欢避免使用终结器,但我仍然不得不说,另一个解决方案是在终结器中调用Signal(然后你可以删除WeakReference的东西):

 ~MyClass()
 {
    _cancellationSignal.Signal();
 }

注意_working被声明为volatile。您也可以使用ManualResetEventSlim甚至CancellationToken来代替。

在这两种方法(WeakReference和终结器),你必须避免传递this引用到线程(因为它会防止你的类实例被垃圾收集),因此我添加了一个CancellationSignal类,并将Worker标记为静态