从拥有对象的 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
为静态。
这是一个简单的例子:
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
为静态。