Thread safe reader-writer queue with C++11 Below is my honest attempt to write thread safe queue using C++11 features. Please review it and provide your comments. 

#include &lt;queue&gt;
#include &lt;condition_variable&gt;
#include &lt;atomic&gt;
#include &lt;iostream&gt;

template &lt;typename T&gt;
class ThreadSafeQueue
{
    std::queue&lt;T&gt; m_queue;
    std::mutex m_mutex;
public :

    void Push(const T&amp; data)
    {
        std::lock_guard&lt;std::mutex&gt; lock(m_mutex);
        m_queue.push(data);
    }

    // Universal reference
    template &lt;typename ...Args&gt;
    void Emplace(Args&amp;&amp;... args)
    {
        std::lock_guard&lt;std::mutex&gt; lock(m_mutex);
        m_queue.emplace(std::forward&lt;Args&gt;(args)...);  
    }

    void PopFront(T&amp; data)
    {
        std::lock_guard&lt;std::mutex&gt; lock(m_mutex);
        data = m_queue.front();
        m_queue.pop();
    }

    void PopFrontNoLock(T&amp; data)
    {
        data = m_queue.front();
        m_queue.pop();
    }

    size_t Size()
    {
        std::lock_guard&lt;std::mutex&gt; lock(m_mutex);
        return m_queue.size();
    }

    bool Empty()
    {
        std::lock_guard&lt;std::mutex&gt; lock(m_mutex);
        return m_queue.empty();
    }

    bool EmptyNoLock()
    {
        return m_queue.empty();
    }

    std::mutex&amp; GetMutex()
    {
        return m_mutex;
    }

};

template &lt;typename T&gt;
class ReaderWriterQueue
{
    ThreadSafeQueue&lt;T&gt; m_safeQueue{};
    std::condition_variable m_condVar{};
    std::atomic&lt;bool&gt; m_writeCompleted{};
public :
    void Push(const T&amp; data)
    {
        m_safeQueue.Push(data);
        m_condVar.notify_one();
    }

    // Universal reference
    template &lt;typename ...Args&gt;
    void Emplace(Args&amp;&amp;... args)
    {
        m_safeQueue.Emplace(std::forward&lt;Args&gt;(args)...);
        m_condVar.notify_one();
    }

    void PopFront(T&amp; data)
    {
        std::unique_lock&lt;std::mutex&gt; lock(m_safeQueue.GetMutex());
        m_condVar.wait(lock, [this] {return (!m_safeQueue.EmptyNoLock() || m_writeCompleted); });
        m_safeQueue.PopFrontNoLock(data);
    }

    void NotifyWriteEnd()
    {
        m_writeCompleted = true;
    }

    bool IsWriteFinished() const
    {
        return m_writeCompleted;
    }

    bool Empty()
    {
        return m_safeQueue.Empty();
    }

};


Driver code to test thread safe queue:

void ProduceData(ReaderWriterQueue&lt;int&gt;&amp; queue)
{
    int i = 0;
    while (i &lt; 10)
    {
        queue.Emplace(i);
        i++;
    }
    queue.NotifyWriteEnd();
    std::cout &lt;&lt; "Finished Writing" &lt;&lt; std::endl;
}

void ReadData(ReaderWriterQueue&lt;int&gt;&amp; queue)
{
    while (!queue.IsWriteFinished() || !queue.Empty())
    {
        int waitTime;
        queue.PopFront(waitTime);
        std::cout &lt;&lt; "popped " &lt;&lt; waitTime &lt;&lt; "\n";
        std::this_thread::sleep_for(std::chrono::seconds(waitTime));
    }
    std::cout &lt;&lt; "Finished Reading" &lt;&lt; std::endl;
}


int main()
{
    ReaderWriterQueue&lt;int&gt; rwQueue;
    std::thread writer(ProduceData, std::ref(rwQueue));
    const int readerThreadCount = 2;
    std::thread readers[readerThreadCount];
    for (int count=0; count &lt; readerThreadCount; count++)
    {
        std::thread reader(ReadData, std::ref(rwQueue));
        readers[count] = std::move(reader);
    }

    if (writer.joinable())
    {
        writer.join();
    }
    for (int count = 0; count &lt; readerThreadCount; count++)
    {
        if (readers[count].joinable())
        {
            readers[count].join();
        }
    }
    return 0;
}
There's no way to notify locked consumers of the write end. You might want to modify PopFront and NotifyWriteEnd to return a special null value to every awaiting consumer (or otherwise wake up all the awaiting consumers and notify them the queue is exhausted) when NotifyWriteEnd() is called. Otherwise you'll need a rather serious contract inherent in your application design, that every consumer should know in advance that it would be able to get a matching producer before starting awaiting on the queue.