From: Rodrigo Kumpera Date: Thu, 19 Jun 2014 15:45:17 +0000 (-0400) Subject: Merge pull request #1074 from esdrubal/bug18421 X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=21f79f8d6e420dc967127c35c00a375f5d10346e;hp=feec6280267e8bdcced861653e5eed0a75f9ea95;p=mono.git Merge pull request #1074 from esdrubal/bug18421 Changed TryPeek to handle race condition with Dequeue. --- diff --git a/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs b/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs index aff2492e021..ea8984394b4 100644 --- a/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs +++ b/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs @@ -132,14 +132,24 @@ namespace System.Collections.Concurrent public bool TryPeek (out T result) { - Node first = head.Next; + result = default (T); + bool update = true; + + while (update) + { + Node oldHead = head; + Node oldNext = oldHead.Next; - if (first == null) { - result = default (T); - return false; - } + if (oldNext == null) { + result = default (T); + return false; + } - result = first.Value; + result = oldNext.Value; + + //check if head has been updated + update = head != oldHead; + } return true; } diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs index 51aeeeb8e89..91436a05b21 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using NUnit.Framework; +using MonoTests.System.Threading.Tasks; namespace MonoTests.System.Collections.Concurrent { @@ -115,6 +116,34 @@ namespace MonoTests.System.Collections.Concurrent CollectionStressTestHelper.RemoveStressTest (new ConcurrentQueue (), CheckOrderingType.InOrder); } + [Test] + public void StressTryPeekTestCase () + { + ParallelTestHelper.Repeat (delegate { + var queue = new ConcurrentQueue (); + queue.Enqueue (new object()); + + const int threads = 10; + int threadCounter = 0; + bool success = true; + + ParallelTestHelper.ParallelStressTest (queue, (q) => { + int threadId = Interlocked.Increment (ref threadCounter); + object temp; + if (threadId < threads) + { + while (queue.TryPeek (out temp)) + if (temp == null) + success = false; + } else { + queue.TryDequeue (out temp); + } + }, threads); + + Assert.IsTrue (success, "TryPeek returned unexpected null value."); + }, 10); + } + [Test] public void CountTestCase() {