Madison Brown
Madison Brown

Reputation: 331

Preventing interleaving in C++

Consider the following example class, which allows one thread to wait for a signal from another thread.

class Sync
{
    std::mutex mtx, access;
    std::condition_variable cv;
    bool waiting;

public:
    Sync()
        : waiting(false)
    {
    }
    Sync(const Sync&);
    ~Sync()
    {
        sendSignal();
    }

    void waitForSignal()
    {
        access.lock();
        if (!waiting)
        {
            std::unique_lock<std::mutex> lck (mtx);
            waiting = true;
            access.unlock();

            // in the time between these two statements, 'sendSignal()' acquires 
            // the lock and calls 'cv.notify_all()', thus the signal was missed. 

            cv.wait(lck);
        }
        else
            access.unlock();
    }
    void sendSignal()
    {
        access.lock();
        if (waiting)
        {
            std::unique_lock<std::mutex> lck (mtx);
            cv.notify_all();
            waiting = false;
        }
        access.unlock();
    }
};

The problem I'm having is that a signal will occasionally be missed due to interleaving during the time between unlocking the 'access' mutex and calling 'wait()' on the condition_variable. How can I prevent this?

Upvotes: 0

Views: 240

Answers (1)

dohashi
dohashi

Reputation: 1841

You should probably only have one mutex. I don't see why you need access. Use mtx to protect the waiting variable and for the condition variable.

class Sync
{
    std::mutex mtx;
    std::condition_variable cv;
    bool waiting;

public:
    Sync()
        : waiting(false)
    {
    }
    Sync(const Sync&);
    ~Sync()
    {
        sendSignal();
    }

    void waitForSignal()
    {
        std::unique_lock lck (mtx);
        if (!waiting)
        {
            waiting = true;

            cv.wait(lck);
        }
    }
    void sendSignal()
    {
        std::unique_lock lck (mtx);
        if (waiting)
        {
            cv.notify_all();
            waiting = false;
        }
    }
};

The waiting variable and the condition variable state are tied together so they should be treated as a single critical section.

Upvotes: 2

Related Questions