Interlock.Exchange和垃圾收集的安全性

时间:2009-11-21 17:17:18

标签: c# .net multithreading interlocked

我有一个我从两个线程访问的对象。一个线程在返回值的对象上调用长时间运行的成员函数。第二个线程更新用于生成该值的对象。

我是否在第一个线程执行时调用Interlock.Exchange来替换第二个线程中的对象: 1.旧线程的自我保留对原始对象的引用。 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();
    }
}

这是否保证始终打印“旧”? 感谢。

3 个答案:

答案 0 :(得分:2)

对象没有被垃圾收集的风险,因为它仍然在旧线程的调用堆栈中被引用。

修改 从你的代码中,mData用“Old”初始化,Update()用“Old”覆盖它,所以它确实会打印“Old”。

如果你的意思是:

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

然后打印结果可以是“新”或“旧”,但很可能是“新”,因为您在打印值之前等待1秒。

我不确定我是否了解您的代码示例与垃圾回收问题之间的关系。

答案 1 :(得分:0)

除了你忘记打电话给t.Start(),是的。

您永远不必担心变量是从您下面收集的垃圾。如果您可以获得对象的引用,则不会对其进行垃圾回收。

答案 2 :(得分:-1)

您的问题似乎是在C#中使用Interlocked.Exchange对象类型的陷阱之一。垃圾收集器也不是那个寻找麻烦的地方。

首先,请记住,您直接更换内存。如果您的mData变量的类型是Disposable,则只能处理最新的副本。互锁中断对象终结。

更令人担忧的是,如果要在mData对象上调用成员函数,这需要很长时间才能执行。这会在成员函数执行时更改self的值。

以下是一些代码,显示了在对象上使用Exchange的问题:     使用系统;     使用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);
        }
    }
}