cameron314 / concurrentqueue

A fast multi-producer, multi-consumer lock-free concurrent queue for C++11
Other
9.53k stars 1.66k forks source link

How to block enqueue? #342

Closed poor1017 closed 1 year ago

poor1017 commented 1 year ago

Hi @cameron314

Thank you for your greate library!

I have a concurrent queue, the producer will generate UUID then enqueue, several consumers will take UUID from the queue. My requirement is: if the queue has enough UUIDs (we can call this as high water level) in it, it will block enqueue, until its UUIDs is lower than a number (we can call this low water level).

If high/low water level is too complex, what about a threshold?

Looking forward to your reply.

cameron314 commented 1 year ago

Sounds like you want to use a semaphore in front of the queue. A LightweightSemaphore is included in this library.

poor1017 commented 1 year ago

@cameron314

Thank you for your suggestion. I think I can implement like this:

  1. Consumers call size_approx() every time they get a UUID;
  2. If size_approx is lower than the low water mark, then sema->signal() is called in consumer thread to notify the producer to continue producing UUIDs;
  3. What I don't know is how to make the producer stop producing UUIDs and block it if size_approx is greater than the high water mark?
  4. In addition, consumers have to call size_approx every time they get a UUID. Will the performance be greatly affected?

Looking forward to your reply.

cameron314 commented 1 year ago

Don't use size_approx, you'll have races.

Set the semaphore to the maximum number of items. Before the producer enqueues, wait on the semaphore. After a consumer dequeues, signal the semaphore.

There will be some overhead, but not much. LightweigthSemaphore is designed to be very efficient in the hot path when no blocking is actually necessary.

poor1017 commented 1 year ago

Hi @cameron314

  1. Before the producer enqueues, wait on the semaphore -> the queue is always empty;
  2. After a consumer dequeues, signal the semaphore -> the consumer is always blocking;

Is this a dead-lock?

cameron314 commented 1 year ago

I don't understand. Why would the queue stay empty? The first N waits on the semaphore would return immediately.

Also, signaling a semaphore is not a blocking operation.

poor1017 commented 1 year ago

@cameron314

Before the producer enqueues, wait on the semaphore.

The queue is empty at beginning, and the semaphore will never get signal.

After a consumer dequeues, signal the semaphore.

Because the queue is always empty, so dequeuing is blocking, so signaling operation can not be excuted.

cameron314 commented 1 year ago

The semaphore would be initialized to some value larger than 0.

poor1017 commented 1 year ago

@cameron314

Your solution works very well, thank you!