Using a condition_variable to Wake a Thread - C++ Thread

C++ examples for Thread:Mutex

Description

Using a condition_variable to Wake a Thread

Demo Code

                                                                                              
#include <condition_variable>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
#include <stack>
#include <vector>
                                                                                              
using namespace std;
                                                                                              
class MyObject/*w w  w .  j  a va  2  s . c  o  m*/
{
private:
    static const unsigned int MAX_OBJECTS{ 8 };
                                                                                              
    using MyCollection = vector < MyObject >;
    static MyCollection s_ManagedObjects;
                                                                                              
    static stack<unsigned int> s_FreeList;
    static mutex s_Mutex;
                                                                                              
    unsigned int m_Value{ 0xFFFFFFFF };
                                                                                              
public:
    MyObject() = default;
    MyObject(unsigned int value)
        : m_Value{ value }
    {
                                                                                              
    }
                                                                                              
    unsigned int GetValue() const { return m_Value; }
                                                                                              
    void* operator new(size_t numBytes)
    {
        lock_guard<mutex> lock{ s_Mutex };
                                                                                              
        void* objectMemory{};
                                                                                              
        if (s_ManagedObjects.capacity() < MAX_OBJECTS)
        {
            s_ManagedObjects.reserve(MAX_OBJECTS);
        }
                                                                                              
        if (numBytes == sizeof(MyObject) &&
            s_ManagedObjects.size() < s_ManagedObjects.capacity())
        {
            unsigned int index{ 0xFFFFFFFF };
            if (s_FreeList.size() > 0)
            {
                index = s_FreeList.top();
                s_FreeList.pop();
            }
                                                                                              
            if (index == 0xFFFFFFFF)
            {
                s_ManagedObjects.push_back({});
                index = s_ManagedObjects.size() - 1;
            }
                                                                                              
            objectMemory = s_ManagedObjects.data() + index;
        }
        else
        {
            objectMemory = malloc(numBytes);
        }
                                                                                              
        return objectMemory;
    }
    void operator delete(void* pMem)
    {
        lock_guard<mutex> lock{ s_Mutex };
                                                                                              
        const intptr_t index{
            (static_cast<MyObject*>(pMem)-s_ManagedObjects.data()) /
            static_cast<intptr_t>(sizeof(MyObject)) };
        if (0 <= index && index < static_cast<intptr_t>(s_ManagedObjects.size()))
        {
            s_FreeList.emplace(static_cast<unsigned int>(index));
        }
        else
        {
            free(pMem);
        }
    }
};
                                                                                              
MyObject::MyCollection MyObject::s_ManagedObjects{};
stack<unsigned int> MyObject::s_FreeList{};
mutex MyObject::s_Mutex;
                                                                                              
using ProducerQueue = vector < unsigned int > ;
                                                                                              
void ThreadTask(
    reference_wrapper<condition_variable> condition,
    reference_wrapper<mutex> queueMutex,
    reference_wrapper<ProducerQueue> queueRef,
    reference_wrapper<bool> die)
{
    ProducerQueue& queue{ queueRef.get() };
                                                                                              
    while (!die.get() || queue.size())
    {
        unique_lock<mutex> lock{ queueMutex.get() };
                                                                                              
        function<bool()> predicate{
            [&queue]()
            {
                return !queue.empty();
            }
        };
        condition.get().wait(lock, predicate);
                                                                                              
        unsigned int numberToCreate{ queue.back() };
        queue.pop_back();
                                                                                              
        cout << "Creating " <<
            numberToCreate <<
            " objects on thread " <<
            this_thread::get_id() << endl;
        for (unsigned int i = 0; i < numberToCreate; ++i)
        {
            MyObject* pObject{ new MyObject(i) };
        }
    }
}
                                                                                              
int main(int argc, char* argv[])
{
    condition_variable condition;
    mutex queueMutex;
    ProducerQueue queue;
    bool die{ false };
                                                                                              
    thread myThread1{ ThreadTask, ref(condition), ref(queueMutex), ref(queue), ref(die) };
    thread myThread2{ ThreadTask, ref(condition), ref(queueMutex), ref(queue), ref(die) };
                                                                                              
    queueMutex.lock();
    queue.emplace_back(300000);
    queue.emplace_back(400000);
    queueMutex.unlock();
                                                                                              
    condition.notify_all();
                                                                                              
    this_thread::sleep_for( 10ms );
    while (!queueMutex.try_lock())
    {
        cout << "Main waiting for queue access!" << endl;
        this_thread::sleep_for( 100ms );
    }
                                                                                              
    queue.emplace_back(100000);
    queue.emplace_back(200000);
                                                                                              
    this_thread::sleep_for( 1000ms );
                                                                                              
    condition.notify_one();
                                                                                              
    this_thread::sleep_for( 1000ms );
                                                                                              
    condition.notify_one();
                                                                                              
    this_thread::sleep_for( 1000ms );
                                                                                              
    queueMutex.unlock();
                                                                                              
    die = true;
                                                                                              
    cout << "main waiting for join!" << endl;
                                                                                              
    myThread1.join();
    myThread2.join();
                                                                                              
    return 0;
}

Result


Related Tutorials