1

2つのスレッドからアクセスしているオブジェクトがあります。1つのスレッドが、値を返すオブジェクトに対して長時間実行されるメンバー関数を呼び出します。2番目のスレッドは、その値を生成するために使用されるオブジェクトを更新します。

Interlock.Exchangeを呼び出して、最初のスレッドの実行中に2番目のスレッドのオブジェクトを置き換えると、次のようになります。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();
    }
}

これは常に「古い」を印刷することが保証されていますか?ありがとう。

4

3 に答える 3

2

オブジェクトはまだ古いスレッドの呼び出しスタックで参照されているため、オブジェクトがガベージコレクションされるリスクはありません。

編集: コードから、mDataは「Old」で初期化され、Update()は「Old」で上書きするため、実際には常に「Old」と出力されます。

あなたが意味した場合:

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

その場合、印刷結果は「New」または「Old」のいずれかになりますが、値を印刷する前に1秒待つため、ほとんどの場合「New」になります。

コードサンプルとガベージコレクションの問題との関係を理解し​​ているかどうかはわかりません。

于 2009-11-21T17:18:39.287 に答える
0

t.Start() を呼び出すのを忘れていることを除けば、はい。

変数が自分の下からガベージ コレクションされることを心配する必要はありません。オブジェクトへの参照を取得できた場合、そのオブジェクトはガベージ コレクションされていません。

于 2009-11-21T19:56:28.050 に答える
-1

あなたの質問は、C#のオブジェクトタイプでInterlocked.Exchangeを使用する際の落とし穴の1つであるようです。ガベージコレクターは、あなたの悩みを探す場所でもありません。

まず、メモリを直接交換することを忘れないでください。mData変数のタイプがDisposableの場合、最新のコピーのみを破棄できます。インターロックはオブジェクトのファイナライズを中断します。

さらに懸念されるのは、実行に時間がかかるmDataオブジェクトのメンバー関数を呼び出す場合です。これにより、実行中にメンバー関数のselfの値が変更されます。

オブジェクトでExchangeを使用する際の問題を示すコードを次に示します。usingSystem; 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);
        }
    }
}
于 2009-11-22T04:17:40.273 に答える