5

Enqueue(T)複数のスレッドから同時に呼び出し、それらのスレッドが完了するのを待ってからDequeue()キューを呼び出したり列挙したりすると、スレッドセーフになりますか?

var queue = new Queue<int>();
Action enqueue = () =>
{
    for (int i = 0; i < 100000; i++)
        queue.Enqueue(i);
};

var tasks = new[]
{
    new Task(enqueue),
    new Task(enqueue),
    new Task(enqueue)
};
foreach (var task in tasks)
    task.Start();

Task.Factory.ContinueWhenAll(tasks, t =>
{
    while (queue.Count > 0)
        Console.WriteLine(queue.Dequeue());
});
4

4 に答える 4

17

ドキュメントには、この型のインスタンス メンバーはスレッド セーフではないことも記載されています(スレッド セーフ セクションまでスクロールします)。

ドキュメントには次のようにも記載されています。

コレクションが変更されない限り、キューは複数のリーダーを同時にサポートできます。

ただし、これは、同時読み取りがリストを変更しないという事実の副産物にすぎません。タイプを「スレッドセーフ」にするわけではありません。スレッド セーフは、型のパブリック コントラクトを定義するすべてのアクションにわたって真のサポートを提供するものと考えるのが最適です(この場合、リストの変更におけるスレッド セーフも)。

冗談めかして: Enqueue の実装には、スレッドの同期やロックのプリミティブは含まれていません。

public void Enqueue(T item)
{
    if (this._size == this._array.Length)
    {
        int num = (int)((long)this._array.Length * 200L / 100L);
        if (num < this._array.Length + 4)
        {
            num = this._array.Length + 4;
        }
        this.SetCapacity(num);
    }
    this._array[this._tail] = item;
    this._tail = (this._tail + 1) % this._array.Length;
    this._size++;
    this._version++;
}

だから私は「いいえ」で行きます。ConcurrentQueueマルチスレッドのサポートがあります。

于 2012-08-24T14:07:57.590 に答える
4

これは重要です。キューがスレッドセーフであるとドキュメントに記載されていない場合は、そうではありません。(そして Queue については、スレッドセーフではないと彼らは言います)。

内部を確認するのは弱いテストです。内部はいつでもスレッドセーフでないバージョンに変更される可能性があります。

異常な状況を除いて、文書化されていないプロパティに依存しないでください。

于 2012-08-24T14:12:29.953 に答える
1

Queue はスレッドセーフではないため、これがスレッドセーフになるとは思いません。同じインスタンスを異なるスレッドで共有しています。

コレクションが変更されない限り、キューは複数のリーダーを同時にサポートできます。それでも、コレクションの列挙は本質的にスレッドセーフな手順ではありません。列挙中のスレッド セーフを保証するために、列挙全体でコレクションをロックできます。読み取りおよび書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。 http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

于 2012-08-24T14:10:44.170 に答える
0

この型の public static (Visual Basic では共有) メンバーは、スレッド セーフです。インスタンス メンバーは、スレッド セーフであるとは限りません。

http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

独自の同期を実装する (つまり、lock() を使用する) か、ConcurrentQueue (System.Collections.Concurrent) を使用する必要があります。

于 2012-08-24T14:09:12.393 に答える