异步操作在析构函数中

问题描述:

尝试在类析构函数中运行异步操作失败。异步操作在析构函数中

这是代码:

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没有提及例如破坏线程/异步方面。

那么有什么想法?

谢谢

+0

'Task.Run'将启动另一个线程,但即使您等待1秒也许这是不够的。您需要等待任务的结果,可能使用'.Wait()'来确保它完成。这就是说我认为在析构函数中启动线程或任务是一个坏主意。应该使用析构函数来清理非托管内存。 – Igor

+1

哇,在GC之后将一个引用传递给另一个线程的想法显然已经将该引用放入终结器队列中了... –

+0

@RenéVogt该文档明确提到析构函数中的代码是在完成对象之前执行的。看到这个锚的底部:https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx#Remarks –

在你的特殊的例子,因为运行时终止与应用程序域正在卸载新线程无法启动。当应用程序域卸载时 - 它将运行所有终结器并关闭所有线程。你可以验证这一点:

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中做这样的事情,而只是为了让你知道真正的原因。

+0

您的答案符合问题,但是 - 您是否熟悉有关此问题的任何官方文档?谢谢 –

+0

我认为很显然,当运行时终止(所以你的进程退出),允许启动新线程并且所有正在运行的线程都被中止是没有意义的。不过,我会尝试在文档上找到一些东西。 – Evk

+0

@SaturnTechnologies不幸的是,我没能在有限的时间内找到关于这个案件的任何具体文件。 – Evk