Search code examples
c++boostqueuelock-free

Can a boost::lockfree::queue be checked for full?


I am using a boost::lockfree::queue Foo(128).

Before Popping the queue I can check the queue for empty status by Foo.empty() function.

I was wondering if I can check similarly for its status at full capacity before Pushing! Couldn't find any resource online explaining how to do it.

Any suggestions?


Solution

  • It appears Boost's LF multi-producer multi-consumer queue implementation doesn't support this. Other MPMC queues might.

    boost::lockfree::spsc_queue (single-producer single-consumer ring-buffer queue) does, with spsc.write_available() > 0.


    boost::lockfree::queue is not fixed-size by default, only if you pass a capacity as a template arg, or fixed_sized<true>. If the data structure is configured as fixed-sized, the internal nodes are stored inside an array and they are addressed by array indexing. (But it's not a ring-buffer like some other MPMC queues.) Otherwise they're dynamically allocated and kept on a free-list.

    For performance you probably should make it fixed-size. Or if you want to limit dynamic allocation, you can use bounded_push instead of push, so it will return false instead of going to the OS for more memory (which might not be lock-free).


    If you are using a queue<fixed_size<true>>, then it is possible for the queue to become full.

    But It wouldn't be very meaningful to check separately because another producer could have made the queue full between the check and the push. Are you looking for a performance optimization like avoiding constructing the object if the queue would probably still be full by the time you're ready to call push?

    (Also, a consumer could make the queue non-full right after you check, so it really only makes sense to check as part of an attempted push. And perhaps there isn't even an efficient lock-free way to check. Otherwise they could have had the function always return true for non-fixed-size queues, and return a meaningful result for fixed-size.)

    This is why push() returns bool: false means the queue was full (or a new node couldn't be allocated for non-fixed-size queues).


    Before Popping the queue I can check the queue for empty status by Foo.empty() function.

    I hope you're not actually doing this; it has all the same problems of racing with other threads as push, and with fewer opportunities to optimize. There's no object to construct before the attempt, you just call pop and see if you get one or not.

    Another thread could have made the queue empty, or made it non-empty, between your check and your actual pop. Unless you're the only consumer, in which case seeing non-empty does mean you can definitely pop. A multi-producer single-consumer use-case would not be compatible with spsc_queue.

    Anyway, this is why it's bool pop(T &); not T pop().