NOTE: It is NOT guaranteed that the result of a push() is accessible to a thread that calls pop() after the push(), because of implementation details. See the body of the function for details.
| 44 | // pop() after the push(), because of implementation details. See the body of the function for |
| 45 | // details. |
| 46 | void push(T elem) { |
| 47 | Node* node = new Node(std::move(elem)); |
| 48 | _approxSize.fetch_add(1, std::memory_order_relaxed); |
| 49 | // ORDERING: must acquire any updates to prev before modifying it, and release our updates |
| 50 | // to node for other producers. |
| 51 | Node* prev = tail.exchange(node, std::memory_order_acq_rel); |
| 52 | // NOTE: If the thread is suspended here, then ALL FUTURE push() calls will be INACCESSIBLE |
| 53 | // by pop() calls until the next line runs. In order to guarantee that a push() is visible |
| 54 | // to a thread that calls pop(), ALL push() calls must have completed. |
| 55 | // ORDERING: must make updates visible to consumers. |
| 56 | prev->next.store(node, std::memory_order_release); |
| 57 | } |
| 58 | |
| 59 | // NOTE: It is NOT safe to call pop() from multiple threads without synchronization. |
| 60 | bool pop(T& elem) { |
no outgoing calls
no test coverage detected