2

次のように、ReadOnlyCollectionを使用したスレッドの多いアプリケーションがあります。

internal static ReadOnlyCollection<DistributorBackpressure44> DistributorBackpressure44Cache
{
    get
    {
        return _distributorBackpressure44;
    }
    set
    {
        _distributorBackpressure44 = value;
    }
}

このコレクションが(常に別のスレッドで)置き換えられるアプリ内の場所が1つあり、次のようになります。

    CicApplication.DistributorBackpressure44Cache = new ReadOnlyCollection<DistributorBackpressure44>(someQueryResults.ToList());

コード内には、通常はLinqクエリを介して、さまざまなスレッドでこのコレクションにアクセスする場所がたくさんあります。多くの場合、コードは次のようになります。

foreach (DistributorBackpressure44 distributorBackpressure44 in CicApplication.DistributorBackpressure44Cache.Where(row => row.Coater == coater && row.CoaterTime >= targetTime).ToList())
{
 ...
 ...
}

私がやっていることは、ロックを行う必要がなく、スレッドセーフだと思いますか?コレクションが別のスレッドで置き換えられるのとまったく同時に発生した場合、上記のクエリで何が起こるかはわかりません。

4

3 に答える 3

5

参照の割り当てはアトミックであるため、はい、スレッドセーフです。ただし、データが書き込まれた直後に読み取る準備ができていることに依存しない場合に限ります。これはキャッシュが原因であるため、これvolatileを防ぐためにをスローすることをお勧めします。

参照の割り当てはアトミックであるため、Interlocked.Exchange(ref Object、Object)が必要なのはなぜですか?も参照してください。

于 2012-11-29T18:34:45.007 に答える
2

それはかなりありそうもないです。スレッドがプロパティを割り当てた後、まったく予測できない瞬間に、他のスレッドが新しいコレクションを確認します。その前に、古い値を読み取ります。これはnullであるか、まったく異なるコンテンツを持つ別のコレクションである可能性があります。

ランダム性はあなたを困らせるものです。これは、コレクションが読み取り専用であるかどうかとは関係がないことに注意してください。スレッドが古い値を使用することは問題ないかもしれませんが、それはあまり一般的ではありません。何よりも、大丈夫だとは言わなかったので、まだ結果を考慮していない可能性があります。あなたはこれを熟考する必要があるでしょう。プロパティゲッターとセッターで自分でできることは何もありません。スレッドはそれらの間でネゴシエートする必要があります。これがスレッド化を困難にし、可変データが共有されるコード内の場所を徹底的に分析することが非常に重要になります。このプロパティのように。

于 2012-11-29T18:50:56.353 に答える
0

あなたの場合は問題ないように思えますが、ReadOnlyCollectionラップしている基になるコレクションが変更されると、問題が発生する可能性があります。

たとえば、次のコードチャンクは、InvalidOperationException「コレクションが変更されました。列挙操作が実行されない可能性があります」というメッセージを含むをスローします。これは、基List<int>になるアイテムが別のスレッドで列挙されているときにアイテムが削除されているためです。

var numbers = new List<int>() {1,2,3,4,5};
var readOnly = new ReadOnlyCollection<int>(numbers);

ThreadPool.QueueUserWorkItem(x => {
    foreach (int number in readOnly)
    {
        Console.WriteLine(number);
        Thread.Sleep(300);
    }
});

Thread.Sleep(150);
numbers.Remove(2);
于 2014-05-27T14:29:25.057 に答える