スレッドセーフな配列(List,Dictionary,Queue,Stack)を作成する。(SyncRoot,Synchronized)ジェネリック版。
基本的に配列の操作はスレッドセーフではないので(あるスレッドが配列に追加・削除している途中で、別スレッドでFor Eachしたら正しく列挙できない)マルチスレッドで配列のデータを操作する場合は、同時に実行されないようにロックする必要があります。
非ジェネリックな配列の型の場合、SyncRootプロパティ、Synchronizedメソッドがありましたがジェネリック型ではIntellisenseに表示されません。ですが、実装されていない訳ではなく、SyncRootの場合はICollectionインタフェースを通じて、Synchronizedメソッドの場合は非ジェネリック型の静的メソッドを通じて、スレッドセーフ化することが出来ます。
■lockステートメントによるスレッドセーフ化
using System;
using System.Collections;
using System.Collections.Generic;namespace ThreadSafeCollection
{
class Program
{static void Main(string[] args)
{Queue
SafeQueue = new Queue (); lock (((ICollection)SafeQueue).SyncRoot)
{
SafeQueue.Enqueue("AddObject");
}}
}
}
■Synchronizedスタティックメソッドによるスレッドセーフ化
ジェネリック型には、Synchronizedメソッドはありません。
と、思っていましたが代替方法があるようです。gsf_zero1さんに教えてもらいました。
[C#] Synchronizedしたコレクションの操作 (Collection, Queue, Synchronized, IsSynchronized, lock, CopyTo)
http://d.hatena.ne.jp/gsf_zero1/20100107/p2
.Net 3.0 からは以下のクラスが使えるようです。
・SynchronizedCollection ジェネリック クラス
・SynchronizedKeyedCollection ジェネリック クラス
・SynchronizedReadOnlyCollection ジェネリック クラス
使用するにはSystem.ServiceModelアセンブリへの参照設定が必要です。
using System;
using System.Collections;
using System.Collections.Generic;namespace ThreadSafeCollection
{
class Program
{
static void Main(string[] args)
{SynchronizedCollection
SafeList = new SynchronizedCollection ;
SafeList.Add("Add Object");}
}
}
SynchronizedCollectionは、型自体がスレッドセーフなのでSynchronizedメソッドを呼び出す必要はありません。
gsf_zero1さんの記事でありますが、For Eachなどの複合処理は保護されないのでlockステートメントによる同期が必要です。