2009-11-21 24 views
1

我有一個對象,我正在從兩個線程訪問。一個線程在返回值的對象上調用一個長時間運行的成員函數。第二個線程更新用於生成該值的對象。Interlock.Exchange和Garbage Collection的安全

我是否在第一個線程正在執行時調用Interlock.Exchange來替換第二個線程中的對象: 1.舊線程的self會保留對原始對象的引用嗎? 2.是否存在原始對象被垃圾收集的風險?

import System; 
import System.Threading; 
import System.Generics; 

class Example { 
    var mData = new String("Old"); 
    public void LongFunction() { 
     Thread.Sleep(1000); 
     Console.WriteLine(mData); 
    } 
    public void Update() { 
     Interlocked.Exchange(ref mData, "Old"); 
    } 
} 

class Program { 
    public static Main(string[] argv) { 
     var e = new Example(); 
     var t = new Thread(new ThreadStart(e.LongFunction())); 
     t.Start(); 
     e.Update(); 
    } 
} 

難道這保證始終打印 「老」? 謝謝。

回答

2

對象沒有被垃圾收集的風險,因爲它仍舊在舊線程的調用棧中被引用。

編輯: 從你的代碼,MDATA被初始化爲「老」和更新()與「老」將覆蓋它,所以事實上它總是會打印出「舊」。

如果你的意思是:

public void Update() 
{ 
    Interlocked.Exchange(ref mData, "New"); 
} 

然後打印結果可以是「新」或「老」,但很可能是「新」,因爲您在打印前值等待1秒。

我不確定我是否理解您的代碼示例和您的垃圾回收問題之間的關係。

0

除了忘記打電話給t.Start(),是的。

你永遠不用擔心從你的垃圾收集的變量。如果您可以獲取對象的引用,它將不會被垃圾收集。

-1

你的問題似乎是在C#中使用Interlocked.Exchange對象類型的缺陷之一。垃圾收集器並不是您尋找麻煩的地方。

首先,請記住,您直接更換內存。如果您的mData變量的類型是Disposable,則只能處理最新的副本。聯鎖會中斷對象。

更多關心的是,如果你正在mData對象上調用一個需要很長時間執行的成員函數。這會在成員函數執行時更改self的值。

下面是一些代碼,顯示了在對象上使用Exchange的問題: using System; using System.Collections.Generic;使用System.Threading的 ;

namespace ConcurrentTest 
{ 
    class ValType : IDisposable 
    { 
     public int I { get; set; } 
     public int Mem() 
     { 
      Thread.Sleep(1000); 
      return I; 
     } 


     void IDisposable.Dispose() 
     { 
      Console.WriteLine("Destroying"); 
     } 
    } 

    class Example 
    { 
     ValType mData = new ValType {I = 0}; 
     public void Print() 
     { 
      Console.WriteLine(mData.I); 
      Thread.Sleep(2000); 
      Console.WriteLine(mData.Mem()); 
     } 

     public void Update() 
     {  
      var data = new ValType() { I = 1 }; 
      Interlocked.Exchange(ref mData, null); 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var e = new Example(); 
      var t = new Thread(new ThreadStart(e.Print)); 
      t.Start(); 
      e.Update(); 
      t.Join(); 
      Console.ReadKey(false); 
     } 
    } 
} 
+0

您很困惑Dispose和finalizer。終止器不會被垃圾收集器顯式調用,終結器也會這樣做。 Interlocked.Exchange不會破壞對象終結...並且您的代碼會拋出NullException。 – 2009-11-22 11:19:16