Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Should GenericQueue.Enqueue work while a different thread has LOCK(GenericQueue) ?

Should GenericQueue.Enqueue work while a different thread has LOCK(GenericQueue) ?

Scheduled Pinned Locked Moved C#
debuggingdata-structurestestingbeta-testingquestion
8 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JoeRip
    wrote on last edited by
    #1

    I have a Generic Queue<privateType> object, myGenericQueue. My application receives events from another application. In my event handler, I asynchronously (and therefore on a different thread) enqueue data to myGenericQueue, using a delegate (myDelegate.beginInvoke). I use a callback method to determine if the Enqueue operation succeeded. Both the asynch method and the callback produce debug output. In my app's main(), a Form Timer periodically pings, at which time I LOCK myGenericQueue, enumerate and dequeue it. Again, more debug output. To test for synchronization problems, I put a long sleep in my dequeue loop, so that myGenericQueue will be locked when my event handlers try to Enqueue data. Here's what I'm seeing, that I don't understand: while myGenericQueue is theoretically LOCKed, my event handlers are still having no problems Enqueuing data. The callbacks fire right away, suggesting no delay, and all of the debug output matches order/timing expectations. All data is making it to myGenericQueue. Is this expected? Why is there no collision with the lock? The documentation for the Generic Queue object says: A Queue<T> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Doesn't this suggest I should be seeing collisions? Here's my dequeuing code:

    lock (myGenericQueue)
    {
    while (myGenericQueue.Count > 0)
    {
    // copy items from queue to List
    myList.Add((privateType)myGenericQueue.Dequeue());

     // REMOVE: DEBUG: HACK: TODO: remove this, testing only!
     System.Diagnostics.Debugger.Log(0, "", "Starting 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
     System.Threading.Thread.Sleep(5000);
     System.Diagnostics.Debugger.Log(0, "", "Coming out of 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
     }
    

    }

    G C 2 Replies Last reply
    0
    • J JoeRip

      I have a Generic Queue<privateType> object, myGenericQueue. My application receives events from another application. In my event handler, I asynchronously (and therefore on a different thread) enqueue data to myGenericQueue, using a delegate (myDelegate.beginInvoke). I use a callback method to determine if the Enqueue operation succeeded. Both the asynch method and the callback produce debug output. In my app's main(), a Form Timer periodically pings, at which time I LOCK myGenericQueue, enumerate and dequeue it. Again, more debug output. To test for synchronization problems, I put a long sleep in my dequeue loop, so that myGenericQueue will be locked when my event handlers try to Enqueue data. Here's what I'm seeing, that I don't understand: while myGenericQueue is theoretically LOCKed, my event handlers are still having no problems Enqueuing data. The callbacks fire right away, suggesting no delay, and all of the debug output matches order/timing expectations. All data is making it to myGenericQueue. Is this expected? Why is there no collision with the lock? The documentation for the Generic Queue object says: A Queue<T> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Doesn't this suggest I should be seeing collisions? Here's my dequeuing code:

      lock (myGenericQueue)
      {
      while (myGenericQueue.Count > 0)
      {
      // copy items from queue to List
      myList.Add((privateType)myGenericQueue.Dequeue());

       // REMOVE: DEBUG: HACK: TODO: remove this, testing only!
       System.Diagnostics.Debugger.Log(0, "", "Starting 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
       System.Threading.Thread.Sleep(5000);
       System.Diagnostics.Debugger.Log(0, "", "Coming out of 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
       }
      

      }

      C Offline
      C Offline
      Colin Angus Mackay
      wrote on last edited by
      #2

      You only mention locking in one place. You have to lock it in both places. Basically, the lock is asking "can I aquire a lock?" and if it can it gets one. If it can't it blocks until it can get one.

      Recent blog posts: *SQL Server / Visual Studio install order *Installing SQL Server 2005 on Vista *Crazy Extension Methods Redux * Mixins My Blog

      J 1 Reply Last reply
      0
      • J JoeRip

        I have a Generic Queue<privateType> object, myGenericQueue. My application receives events from another application. In my event handler, I asynchronously (and therefore on a different thread) enqueue data to myGenericQueue, using a delegate (myDelegate.beginInvoke). I use a callback method to determine if the Enqueue operation succeeded. Both the asynch method and the callback produce debug output. In my app's main(), a Form Timer periodically pings, at which time I LOCK myGenericQueue, enumerate and dequeue it. Again, more debug output. To test for synchronization problems, I put a long sleep in my dequeue loop, so that myGenericQueue will be locked when my event handlers try to Enqueue data. Here's what I'm seeing, that I don't understand: while myGenericQueue is theoretically LOCKed, my event handlers are still having no problems Enqueuing data. The callbacks fire right away, suggesting no delay, and all of the debug output matches order/timing expectations. All data is making it to myGenericQueue. Is this expected? Why is there no collision with the lock? The documentation for the Generic Queue object says: A Queue<T> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Doesn't this suggest I should be seeing collisions? Here's my dequeuing code:

        lock (myGenericQueue)
        {
        while (myGenericQueue.Count > 0)
        {
        // copy items from queue to List
        myList.Add((privateType)myGenericQueue.Dequeue());

         // REMOVE: DEBUG: HACK: TODO: remove this, testing only!
         System.Diagnostics.Debugger.Log(0, "", "Starting 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
         System.Threading.Thread.Sleep(5000);
         System.Diagnostics.Debugger.Log(0, "", "Coming out of 5 sec sleep at: " + DateTime.Now.Ticks + Environment.NewLine);
         }
        

        }

        G Offline
        G Offline
        Guffa
        wrote on last edited by
        #3

        JoeRip wrote:

        Is this expected?

        Yes.

        JoeRip wrote:

        Why is there no collision with the lock?

        Because you are not using the lock correctly. The lock doesn't protect the object that you are referring to in any way, the object is only used as an identifier. What the lock does is to prevent another code block locking with the same identifier to be entered (or the same code block to be reentered by another thread). So, to protect your queue, you need a lock around every piece of code that uses the queue.

        Despite everything, the person most likely to be fooling you next is yourself.

        1 Reply Last reply
        0
        • C Colin Angus Mackay

          You only mention locking in one place. You have to lock it in both places. Basically, the lock is asking "can I aquire a lock?" and if it can it gets one. If it can't it blocks until it can get one.

          Recent blog posts: *SQL Server / Visual Studio install order *Installing SQL Server 2005 on Vista *Crazy Extension Methods Redux * Mixins My Blog

          J Offline
          J Offline
          JoeRip
          wrote on last edited by
          #4

          How... odd. The documentation of "lock" at http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx[^] makes no mention at all about having to use lock on both sides. In fact, the example quite clearly shows the lock being applied in only one place, and the lock still preventing another thread from accessing that code...

          C 1 Reply Last reply
          0
          • J JoeRip

            How... odd. The documentation of "lock" at http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx[^] makes no mention at all about having to use lock on both sides. In fact, the example quite clearly shows the lock being applied in only one place, and the lock still preventing another thread from accessing that code...

            C Offline
            C Offline
            Colin Angus Mackay
            wrote on last edited by
            #5

            JoeRip wrote:

            In fact, the example quite clearly shows the lock being applied in only one place,

            That is because the one place is being used by multiple threads. It is being used on ALL (10) sides, in that example.

            Recent blog posts: *SQL Server / Visual Studio install order *Installing SQL Server 2005 on Vista *Crazy Extension Methods Redux * Mixins My Blog

            J 1 Reply Last reply
            0
            • C Colin Angus Mackay

              JoeRip wrote:

              In fact, the example quite clearly shows the lock being applied in only one place,

              That is because the one place is being used by multiple threads. It is being used on ALL (10) sides, in that example.

              Recent blog posts: *SQL Server / Visual Studio install order *Installing SQL Server 2005 on Vista *Crazy Extension Methods Redux * Mixins My Blog

              J Offline
              J Offline
              JoeRip
              wrote on last edited by
              #6

              Yeah, I figured out my error in thinking. I was so used to using lock (myQueue.SyncRoot) that I had come to think of it as locking the Queue itself, not setting a lock flag on one of the queue's members. Turns out all I needed to do for my Generic Queues - which I thought didn't have a SyncRoot member, since it didn't show up in VS 2008's Intellisense :-), was to use

              lock (((ICollection)myGenericQueue).SyncRoot)
              {
              }

              It was good to be reminded of what the lock statement was actually doing, though. Thanks!

              G 1 Reply Last reply
              0
              • J JoeRip

                Yeah, I figured out my error in thinking. I was so used to using lock (myQueue.SyncRoot) that I had come to think of it as locking the Queue itself, not setting a lock flag on one of the queue's members. Turns out all I needed to do for my Generic Queues - which I thought didn't have a SyncRoot member, since it didn't show up in VS 2008's Intellisense :-), was to use

                lock (((ICollection)myGenericQueue).SyncRoot)
                {
                }

                It was good to be reminded of what the lock statement was actually doing, though. Thanks!

                G Offline
                G Offline
                Guffa
                wrote on last edited by
                #7

                No, that doesn't protect the queue. You still have to use a lock around every piece of code that uses the queue.

                Despite everything, the person most likely to be fooling you next is yourself.

                J 1 Reply Last reply
                0
                • G Guffa

                  No, that doesn't protect the queue. You still have to use a lock around every piece of code that uses the queue.

                  Despite everything, the person most likely to be fooling you next is yourself.

                  J Offline
                  J Offline
                  JoeRip
                  wrote on last edited by
                  #8

                  Agreed, I should have made that clear. I was just explaining why I thought the lock (object) call was actually protecting the object. And, I was just noting that the lock (((ICollection)myGenericQueue).SyncRoot) statement gives me a nice shared object to lock that can be used by my library code and its callers. I was happy to find I could still do this with Generic Queues, the way I had with... uh, non-generic queues. Specific queues?

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups