Reputation: 9906
I have two threads, a producer and a consumer.
The producer might not always be producing something. The consumer however, needs to consume it as soon as it becomes available.
The producer thread works in a loop and puts results into a ConcurrentQueue
. The consumer thread is in a while (!disposing)
loop that calls AutoResetEvent.WaitOne
when the system becomes disabled. I've considered calling AutoResetEvent.WaitOne
also in the case when the ConcurrentQueue.TryDequeue
method returns false; this should only ever happen when there are no items left in the queue.
However, if I were to do this, a deadlock could occur when the following execution is done:
This is a possibility in this snippet:
while (this.isDisposing == 0)
{
if (this.isEnabled == 0)
{
this.signal.WaitOne();
}
object item;
if (!this.queue.TryDequeue(out item))
{
this.signal.WaitOne();
continue;
}
this.HandleItem(item);
}
What is the proper way to do this without using locks?
Upvotes: 1
Views: 580
Reputation:
The problem here is that thread pausing is in almost all operating systems a kernel level event. Windows I think with Fibers permits user-level pausing/unpausing, but that's all I know of.
So you locklessly whizz along with your queue, but how do you signal when there is something in the queue in the first place?
Signalling implies sleeping - and that's the problem. You can do lock-free signalling, but waiting, well, you gotta call the OS equivelent of WaitForEvent(), and that's a problem, because you don't WANT to be using these slow, OS provided mechanisms.
Basically, there's no or very litle OS support for this yet.
Upvotes: 0
Reputation: 3531
I think the BlockingCollection would be good to use here. It will wait efficiently until there is data in the queue. You can combine this with a ConcurrentQueue I think. See http://msdn.microsoft.com/en-us/library/dd267312.aspx
Upvotes: 1