2017-04-06 73 views
1

嘗試在類析構函數中運行異步操作失敗。異步操作在析構函數中

這是代碼:

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 –

回答

2

在你的特殊的例子,因爲運行時終止與應用程序域正在卸載新線程無法啓動。當應用程序域卸載時 - 它將運行所有終結器並關閉所有線程。你可以驗證這一點:

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