With while(pop_if_present(...)) you do brute force waiting for a wait (also called spinning) on the queue. When the queue is empty, you cycle the waste by keeping the CPU busy until the item is queued by another thread running on another processor or OS, deciding to give your processor some other, possibly unrelated thread / process.
You can see how this can be bad if you have only one processor - the manufacturer’s thread will not be able to press and, thus, stop the consumer’s rotation, until at least the consumer’s end is time sliced plus the overhead <context switch. Clear mistake.
With multiple CPUs, this can be better if the OS selects (or forces) the manufacturers flow to work on different CPUs. This is the main idea of spin-lock - a synchronization primitive built directly on special processor instructions, such as compare and-swap or related to loading / saving, and usually used inside the operating system to exchange data between interrupt handlers and the rest of the kernel and to build constructions more high level such as semaphores .
With pop() blocking, if the queue is empty, you enter sleep wait , that is, you request the OS to put the consumer thread in a state without scheduling, until the event clicks on the queue, another thread forms. The key point here is that the processor is available for other (hopefully useful) jobs. The TBB implementation is actually trying to avoid sleep, as it is expensive (entering the kernel, rescheduling, etc.). The goal is to optimize the normal case when the queue is not empty, and the element can be quickly found.
The choice is really simple, but always - expectations of expectation, i.e. pop() blocking, unless you have to wait in standby mode (and this is in real-time systems, the context of OS interruption, and some very specialized applications).
Hope this helps a bit.
source share