[Mono-dev] ConcurrentQueue<T> issues (repros)

Greg Young gregoryyoung1 at gmail.com
Thu Sep 20 13:38:58 UTC 2012


Here are some tests that show some of the failure modes of concurrent
queue (all work in CLR impl)

On my machine (8 cores within 1 second of running for all failures).
The worst is the last one where anything larger than a reference gives
partial reads.

in gist if you prefer: https://gist.github.com/3755979

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance
of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[T].TryDequeue
(System.Collections.Concurrent.T& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueReference>c__AnonStorey1.<>m__0
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException:
Object reference not set to an instance of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[T].TryDequeue
(System.Collections.Concurrent.T& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueReference>c__AnonStorey1.<>m__0
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0



        private static void TestMonoConcurrentQueueReference()
        {
            var queue = new ConcurrentQueue<object>();
            var waits = new List<AutoResetEvent>();
            for (int i = 0; i < 5; i++)
            {
                int q = i;
                waits.Add(new AutoResetEvent(false));
                var t = new Thread(x =>
                {
                    for (int j = 0; j < 100000000; j++)
                    {
                        if (j % 1000000 == 0) Console.Write(".");
                        queue.Enqueue(new object());
                        object item;
                        if (queue.TryDequeue(out item))
                        {

                        }
                    }
                    waits[q].Set();
                });
                t.Start();
            }
            Console.WriteLine("waiting.");
            waits.ForEach(x => x.WaitOne());
            Console.WriteLine("done.");

        }


I end up in the else {} on try dequeue here don't think I should ever
be allowed to (and dont end up there in MS impl)

        struct TestStruct
        {
            public long X;
            public long Y;

            public TestStruct(long x, long y) : this()
            {
                X = x;
                Y = y;
            }
        }

        private static void TestMonoConcurrentQueueBiggerThanReference()
        {
            var queue = new ConcurrentQueue<TestStruct>();
            var waits = new List<AutoResetEvent>();
            for(int i=0;i<5;i++)
            {
                int q = i;
                waits.Add(new AutoResetEvent(false));
                var t = new Thread(x =>
                                       {
                                           for(int j=0;j<100000000;j++)
                                           {
                                               if(j% 1000000 == 0)
Console.Write(".");
                                               queue.Enqueue(new
TestStruct(0x11223344, 0x99887766));
                                               TestStruct item;
                                               if(queue.TryDequeue(out item))
                                               {
                                                   if(item.X !=
0x11223344) throw new Exception("bad x");
                                                   if(item.Y !=
0x99887766) throw new Exception("bad y");
                                               } else
                                               {
                                                   throw new
Exception("unable to read."); <~~~~ should never hit this.
                                               }
                                           }
                                           waits[q].Set();
                                       });
                t.Start();
            }
            Console.WriteLine("waiting.");
            waits.ForEach(x => x.WaitOne());
            Console.WriteLine("done.");

        }


For good measure lets take out the exception in the last about not
being able to read when it should be able to (eg comment out the
throw)

Unhandled Exception:
System.Exception: bad y
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance
of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance
of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance
of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance
of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Exception: bad y
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException:
Object reference not set to an instance of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException:
Object reference not set to an instance of an object
  at System.Collections.Concurrent.ConcurrentQueue`1[ConsoleApplication1.Program+TestStruct].TryDequeue
(ConsoleApplication1.TestStruct& result) [0x00000] in <filename
unknown>:0
  at ConsoleApplication1.Program+<TestMonoConcurrentQueueBiggerThanReference>c__AnonStorey3.<>m__2
(System.Object x) [0x00000] in <filename unknown>:0
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0


    private static void TestMonoConcurrentQueueBiggerThanReference()
        {
            var queue = new ConcurrentQueue<TestStruct>();
            var waits = new List<AutoResetEvent>();
            for(int i=0;i<5;i++)
            {
                int q = i;
                waits.Add(new AutoResetEvent(false));
                var t = new Thread(x =>
                                       {
                                           for(int j=0;j<100000000;j++)
                                           {
                                               if(j% 1000000 == 0)
Console.Write(".");
                                               queue.Enqueue(new
TestStruct(0x11223344, 0x99887766));
                                               TestStruct item;
                                               if(queue.TryDequeue(out item))
                                               {
                                                   if(item.X !=
0x11223344) throw new Exception("bad x");
                                                   if(item.Y !=
0x99887766) throw new Exception("bad y");
                                               } else
                                               {
                                                   //throw new
Exception("unable to read."); <~~~~ should never hit this.
                                               }
                                           }
                                           waits[q].Set();
                                       });
                t.Start();
            }
            Console.WriteLine("waiting.");
            waits.ForEach(x => x.WaitOne());
            Console.WriteLine("done.");

        }

-- 
Le doute n'est pas une condition agréable, mais la certitude est absurde.


More information about the Mono-devel-list mailing list