Merge pull request #1074 from esdrubal/bug18421
authorRodrigo Kumpera <kumpera@gmail.com>
Thu, 19 Jun 2014 15:45:17 +0000 (11:45 -0400)
committerRodrigo Kumpera <kumpera@gmail.com>
Thu, 19 Jun 2014 15:45:17 +0000 (11:45 -0400)
Changed TryPeek to handle race condition with Dequeue.

mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs
mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs

index aff2492e0216df7ba60de976dbaf34a158b26fae..ea8984394b46030245c00440b404dd639de7b2e9 100644 (file)
@@ -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;
                }
                
index 51aeeeb8e89b522ea4e2d263b27d3a91fcc72b97..91436a05b2127ccce3817228f27378facd793db7 100644 (file)
@@ -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<int> (), CheckOrderingType.InOrder);
                }
                
+               [Test]
+               public void StressTryPeekTestCase ()
+               {
+                       ParallelTestHelper.Repeat (delegate {
+                               var queue = new ConcurrentQueue<object> ();
+                               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()
                {