Turn a non-blocking concurrent queue into a blocking concurrent queue Microsoft Visual Studio offers a non-blocking concurrent queue class, concurrency::concurrent_queue, based on Intel's TBB. I am using this as a base for a blocking single producer, single consumer concurrent queue.

I am overriding the push and try_pop methods:

#include &lt;concurrent_queue.h&gt;
/**
 * Single producer, single consumer blocking concurrent queue.
 */
template&lt;typename T&gt;
class SPSCBlockingQueue final : public concurrency::concurrent_queue&lt;T&gt;
{
  public:

    /**
     * Push an element to the back of the queue.
     */
    void push(const T&amp; src)
    {
        _push(src);
    }

    /**
     * Push an element to the back of the queue.
     */
    void push(T&amp;&amp; src)
    {
        _push(std::move(src));
    }

    /**
     * Pop an element from the head of the queue. This method will wait
     * until there is an item in the queue that can be dequeued.
     *
     * @param dest a reference to a location to store the dequeued item
     * @return {@code true} if an item was successfully dequeued, otherwise {@code false}
     */
    bool try_pop(T&amp; dest)
    {
        std::unique_lock&lt;std::mutex&gt; lock(_mtx);

        auto res = concurrency::concurrent_queue&lt;T&gt;::try_pop(dest);
        if (!res)
        {
            // The queue must be empty.
            hasData = false;

            // Wait until there is some data...
            _cv.wait(lock, [&amp;] { return hasData; });

            // This should now work.
            res = concurrency::concurrent_queue&lt;T&gt;::try_pop(dest);
        }

        // res should be true.
        return res;
    }

    /**
     * Pop an element from the head of the queue. This method will wait
     * until there is an item in the queue that can be dequeued.
     *
     * @return the dequeued item.
     */
    T pop()
    {
        T dest;
        try_pop(dest);
        return dest;
    }

  private:

    std::mutex _mtx;
    std::condition_variable _cv;
    bool hasData = false;

    template&lt;typename E&gt;
    void _push(E&amp;&amp; src)
    {
        bool notify = false;

        std::unique_lock&lt;std::mutex&gt; lock(_mtx);
        if (!hasData)
        {
            notify = true;
            hasData = true;
        }

        concurrency::concurrent_queue&lt;T&gt;::push(std::forward&lt;E&gt;(src));

        lock.unlock();

        if (notify)
            _cv.notify_one();
    }
};


Here is some unit test code, using the Google test framework:

TEST(CheckTools, BlockingQueue)
{
    enum Data { D1, D2, D3, DataEnd };
    SPSCBlockingQueue&lt;Data&gt; q;

    auto dataElements = {
        D2, D1, D2, D3, D2, D1, D1, D3, D3, D1,
        D1, D2, D1, D3, D2, D2, D3, D2, D1
    };

    vector&lt;Data&gt; dataToPush = dataElements;
    vector&lt;Data&gt; result;

    // Consumer thread...
    auto t = thread([&amp;]
    {
        while (true)
        {
            auto dataEle = q.pop();

            if (dataEle == DataEnd)
                break;

            result.push_back(dataEle);
        }
    });

    // Producer code...
    auto i=0;
    for (auto e : dataToPush)
    {
        if (i++ % 3 == 0)
            this_thread::sleep_for(chrono::milliseconds(250));

        q.push(e);
        i++;
    }

    q.push(DataEnd);
    t.join();

    ASSERT_EQ(result, vector&lt;Data&gt;{ dataElements });
}


I am interested in comments regarding efficiency and correctness.
As a matter of consistency, we don't need to separate typename declaration for this private function void _push(T&amp;&amp; src), and we can depend on the typename declaration on the class level.

void _push(T&amp;&amp; src)
{
    bool notify = false;

    std::unique_lock&lt;std::mutex&gt; lock(_mtx);
    if (!hasData)
    {
        notify = true;
        hasData = true;
    }

    concurrency::concurrent_queue&lt;T&gt;::push(std::forward&lt;T&gt;(src));

    lock.unlock();

    if (notify)
        _cv.notify_one();
}

bool try_pop(T&amp; dest) is not part of public interface, so we can define it as private.
We can depend on std::forward and modify the interfaces for push as follows:

void push(const T&amp;&amp; src)
{
    _push(std::forward&lt;T&gt;(src));
}
void push(T&amp;&amp; src)
{
   _push(std::forward&lt;T&gt;(src));
}



After adapting all these changes it should be as follows. Please note I don't have the system to compile this code from my end.

#include &lt;concurrent_queue.h&gt;
/**
 * Single producer, single consumer blocking concurrent queue.
 */
template&lt;typename T&gt;
class SPSCBlockingQueue final : public concurrency::concurrent_queue&lt;T&gt;
{
  public:

    void push(const T&amp;&amp; src)
    {
        _push(std::forward&lt;T&gt;(src));
    }
    void push(T&amp;&amp; src)
    {
        _push(std::forward&lt;T&gt;(src));
    }

    /**
     * Pop an element from the head of the queue. This method will wait
     * until there is an item in the queue that can be dequeued.
     *
     * @return the dequeued item.
     */
    T pop()
    {
        T dest;
        try_pop(dest);
        return dest;
    }

  private:

    std::mutex _mtx;
    std::condition_variable _cv;
    bool hasData = false;

    bool try_pop(T&amp; dest)
    {
        std::unique_lock&lt;std::mutex&gt; lock(_mtx);

        auto res = concurrency::concurrent_queue&lt;T&gt;::try_pop(dest);
        if (!res)
        {
            // The queue must be empty.
            hasData = false;

            // Wait until there is some data...
            _cv.wait(lock, [&amp;] { return hasData; });

            // This should now work.
            res = concurrency::concurrent_queue&lt;T&gt;::try_pop(dest);
        }

        // res should be true.
        return res;
    }


    void _push(T&amp;&amp; src)
    {
        bool notify = false;

        std::unique_lock&lt;std::mutex&gt; lock(_mtx);
        if (!hasData)
        {
            notify = true;
            hasData = true;
        }

        concurrency::concurrent_queue&lt;T&gt;::push(std::forward&lt;T&gt;(src));

        lock.unlock();

        if (notify)
            _cv.notify_one();
    }
};