异步操作在析构函数中
问题描述:
尝试在类析构函数中运行异步操作失败。异步操作在析构函数中
这是代码:
public class Executor
{
public static void Main()
{
var c1 = new Class1();
c1.DoSomething();
}
}
public class Class1
{
public void DoSomething()
{
}
private int _i = 100;
private int _j = 100;
~Class1()
{
Task.Run(() => _j *= 2); //Does not progress _j
_i *= 2; //Progress _i from 100 to 200
Thread.Sleep(1000);
Console.WriteLine("In destructor. _i = " + _i);
Console.WriteLine("In destructor. _j = " + _j);
}
}
,输出是:
In destructor. _i = 200
In destructor. _j = 100
继Destructor page on MSDN没有提及例如破坏线程/异步方面。
那么有什么想法?
谢谢
答
在你的特殊的例子,因为运行时终止与应用程序域正在卸载新线程无法启动。当应用程序域卸载时 - 它将运行所有终结器并关闭所有线程。你可以验证这一点:
Console.WriteLine("shutdown:" + Environment.HasShutdownStarted);
这将返回true
在你的情况。如果修改您例子是这样的:
class Program {
static void Main(string[] args) {
var c1 = new Class1();
c1.DoSomething();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
}
}
public class Class1
{
public void DoSomething()
{
}
private volatile int _i = 100;
private volatile int _j = 100;
~Class1()
{
Console.WriteLine("shutdown:" + Environment.HasShutdownStarted);
Task.Run(() => _j *= 2); //Does not progress _j
//_i *= 2; //Progress _i from 100 to 200
Thread.Sleep(1000);
Console.WriteLine("In destructor. _i = " + _i);
Console.WriteLine("In destructor. _j = " + _j);
}
}
和编译与优化拍摄模式 - 你会看到,现在运行时不会终止和你的任务将会运行得很好。
很显然,你不应该在finalizer中做这样的事情,而只是为了让你知道真正的原因。
'Task.Run'将启动另一个线程,但即使您等待1秒也许这是不够的。您需要等待任务的结果,可能使用'.Wait()'来确保它完成。这就是说我认为在析构函数中启动线程或任务是一个坏主意。应该使用析构函数来清理非托管内存。 – Igor
哇,在GC之后将一个引用传递给另一个线程的想法显然已经将该引用放入终结器队列中了... –
@RenéVogt该文档明确提到析构函数中的代码是在完成对象之前执行的。看到这个锚的底部:https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx#Remarks –