Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Dr. Dobbs implemented a lock-free queue <a href="http://www.drdobbs.com/cpp/208801974" rel="nofollow noreferrer">in C++</a>, which you could relatively easily adopt to C#. It works when there is exactly one producer (there can be any number of consumers).</p> <p>The basic idea is to use a doubly-linked list as the underlying structure along with a movable head and tail reference. When an item is produced, it gets added to the end, and everything between the beginning of the list and the current "head" is removed. To consume, attempt to move the head up; if it hits the tail, fail, if it doesn't, succeed and return the new element. The particular order of operations makes it inherently thread-safe.</p> <p>However, there are two major problems with using such a "lock-free" design here:</p> <ol> <li><p>There is no way to enforce an upper bound to the queue size, which might be a serious problem if your producer is faster than your consumer;</p></li> <li><p>By design, the <code>Consume</code> method must simply fail to retrieve an element if nothing has been produced. That means you need to implement your <em>own</em> locking for the consumer, and such locking is invariably either busy-waiting (which is <strong>much worse</strong> than locking in the performance spectrum) or timed waits (which slows down your consumer even further).</p></li> </ol> <p>For these reasons, I'd recommend that you seriously consider whether or not you really need a lock-free structure. A lot of people come to this site thinking that it's going to be "faster" than an equivalent structure using locking, but the practical difference for most applications is so negligible that it's normally not worth the added complexity, and in some cases it can actually perform <em>worse</em>, because wait states (or alertable waits) are much cheaper than busy-waiting.</p> <p>Multicore machines and the need for memory barriers make effective lock-free threading even more complicated; under normal operation you can still get out-of-order execution, and in .NET the jitter can further decide to reorder instructions, so you'd probably need to pepper the code with <code>volatile</code> variables and <code>Thread.MemoryBarrier</code> calls, which again might contribute toward making the lock-free version costlier than the basic synchronized version.</p> <p>How about using a plain old synchronized producer-consumer queue first, and <strong>profiling</strong> your application to determine whether or not it can meet your performance requirements? There's a great, efficient P-C queue implementation over at <a href="http://www.albahari.com/threading/part4.aspx" rel="nofollow noreferrer">Joseph Albahari's site</a>. Or, as Richard mentions, if you are using the .NET 4.0 framework then you can simply use <a href="http://msdn.microsoft.com/en-us/library/dd267265%28VS.100%29.aspx" rel="nofollow noreferrer">ConcurrentQueue</a> or more likely <a href="http://msdn.microsoft.com/en-us/library/dd267312%28v=VS.100%29.aspx" rel="nofollow noreferrer">BlockingCollection</a>.</p> <p>Test first - load test the synchronized queue, which is easy to implement - and watch how much time is actually spent locking. Not <em>waiting</em>, which you'd have to do anyway, but on actually <em>acquiring</em> and <em>releasing</em> the locks after they become signaled. If it's more than 1% of your program's execution time, I would be very surprised; but if so, <em>then</em> start looking at lock-free implementations - and make sure you profile those too, to make sure that they're actually performing better.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload