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

Is it OK to stop a thread from the owning objects Dispose method?

这是一个简单的例子:

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 将不会被调用,除非您明确地或通过在 using 语句中包含 MyClass 实例来调用它。

Will Dispose() even be called while the thread is still running?

可以这样调用:

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

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

(虽然你的变量应该是volatile来表示该字段可能被多个线程修改)

但需要注意的重要一点是,Dispose 并没有什么神奇的地方,甚至 using 语句也会翻译成 try-finally ,其中 Dispose 是明确的在 finally 块中调用。

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

您可以用 WeakReference 包裹 class 实例。一旦引用被垃圾回收,线程应该停止工作。

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 被声明为可变的。您也可以使用 ManualResetEventSlim 甚至 CancellationToken

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