2012-02-13 5 views
7

あるスレッドからの書き込みにアクセスする汎用のQueue<T>System.Collections.Generic)があります。また、読み込みのために別のスレッドからアクセスする必要があります。キュー全体をコピーしていますか?<T>演算子「=」スレッドセーフ(C#)

性能上の理由から、プロセス同期(ConcurrentQueue<T>の使用を含む)を実行したくありません。そこで、キュー全体を同じタイプの別のキューオブジェクトにコピーするアイデアを読んでいました。読み取りスレッドの後続の操作は、コピーで実行されます。コピーは簡単なオペレータ=で行います。ここで

は、いくつかの擬似コードです:

//Creating main queue 
Queue<MyType> queue1 = new Queue<MyType>(); 

の書き込みスレッド:スレッドを読む

//Perform writing in the main queue 
queue1.Enqueue(object); 
... 
queue1.Dequeue(); 

//Copy main queue 
Queue<MyType> queue2 = queue1; 
//perform all operations in reading thread on queue2 

だから、このようなソリューションのスレッドが安全なのですか?

UPD:ありがとう、私はこれが単にリンクをコピーしていることに気づいていませんでした。スレッドセーフな方法でオブジェクト全体を値でコピーする方法はありますか?

+0

キューを別のスレッドに公開した後にキューを変更しないと、スレッドセーフになります。 – Steven

+0

通常、「キュー」はプロデューサ/コンシューマのシナリオで使用されることを意味します。つまり、1つのスレッドがそれに書き込みを行い、もう1つのスレッドがそこから読み取ります。毎回それをコピーするのはあまり意味がありません(あなたはどんなコレクションタイプも使うことができ、同じように動作します)。単一の共有キューを使用して、単一のアイテムをデキューしている間にまもなくロックするか、以下のような 'ConcurrentQueue'を使用する必要があります。 – Groo

答えて

11

Queue<T>は参照型です。したがってqueue1queue2に割り当てると、キュー自体ではなく参照のみがコピーされます。

割り当て自体はアトミックなので、スレッドセーフです。 1つのスレッドでqueue1にアクセスし、別のスレッドでqueue2にアクセスすることは、両方からqueue1にアクセスすることが安全ではありません。すなわち、それは安全ではない。

私はConcurrentQueue<T>が "ロックレス"プログラミング手法(Interlocked.Exchangeと友人)を使用していると信じていてかなり速いです。解決策として除外する前に、最初にベンチマークを行う必要があります。

Queue<T>のコピーは確かにConcurrentQueue<T>を使用するよりも遅くなります。私の2.6GHzのシステムConcurrentQueue<object>


Queue<object>で40百万毎秒1500万エンキュー/デキューのペアを管理します。したがって、Queue<object>は約3倍の速さです。

エンキュー/デキューのペアのCPUサイクルはかなり安いです。それがボトルネックの場合は、キュー内の細かい項目を使用してみてください。

+0

これは参考になります。ありがとう! –

1

短答 - いいえ、スレッドセーフではありません

キュー自体をコピーしていないことに注意してください.1つのキューに参照をコピーしています。 (参照の割り当てはアトミックなので、あなたのqueue2 = queue1行は問題ではありません。スレッドセーフではないキューを使用しているためです)

2

Queueのインスタンスはコピーされません。それは参照自体をコピーするだけです。参照のコピーはアトミックですが、新しい参照は、同じインスタンスを指しています。複数のスレッドからインスタンスを変更すると、ではなく、同期なしでスレッドセーフになります。

0

この方法でコレクションをコピーすると、オブジェクトの浅いコピーが作成されます。つまり、参照を同じキューにコピーするだけです。これはスレッドセーフです。

ディープコピーを行うことを意図している場合。それを参照してくださいthisポストは、オブジェクトの深いコピーを実行する際にお手伝いをすることができます。 @ CodeInChaosは本当に良い点がありますが。この方法でオブジェクト全体をコピーするのは確かにConcurentQueue<T>を使用するよりも遅くなります。ここで

+1

そのような深いコピーは非常に醜いです。そして、確かに 'ConcurrentQueue 'を使うよりも遅いです。 – CodesInChaos

+0

@CodeInChaos - 私は知っていますが、彼は自分の投稿でConcurrentQueue を使用したくないと言います。だから私はそれを提案しませんでした。 – TheBoyan

0

MSDNは、スレッドの安全性について述べているものです。

キューは限りコレクションが変更されないように、同時に複数のリーダーをサポートすることができます。それでも、コレクションを列挙することは、本質的にスレッドセーフな手順ではありません。列挙中のスレッドの安全性を保証するために、列挙全体の中でコレクションをロックすることができます。読み取りと書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

関連する問題