2009-11-21 44 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