Nosturion
Nosturion

Reputation: 309

Synchronization with blocking call

Suppose I have a class with the following interface:

class IEvent
{
    void SetEvent() = 0;
    void WaitForEvent() = 0;
}

WaitForEvent() is a blocking function which waits until another thread calls SetEvent() function.

I'm writing unit tests for this class and want following scenario:

First thread calls WaitForEvent(). After that second thread calls SetEvent().

How to synchronize this threads that SetEvent() call will always follow WaitForEvent() call?

I don't want to use any sleeps because I want unit tests to run as fast as possible.

Upvotes: 0

Views: 714

Answers (1)

Richard Hodges
Richard Hodges

Reputation: 69854

This was the best I could manage

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>

class IEvent
{
public:
    virtual void SetEvent() = 0;
    virtual void WaitForEvent() = 0;
};

class EventClass : public IEvent
{
public:
    void SetEvent() override {
        std::unique_lock<std::mutex> lock { _mutex };
        std::cout << "setting event\n";
        _event = true;
        lock.unlock();
        _cv.notify_all();
    }

    void WaitForEvent() override {
        std::unique_lock<std::mutex> lock { _mutex };
        std::cout << "waiting for event\n";
        _cv.wait(lock, [this]{ return _event; });
        std::cout << "waiting complete\n";
    };

private:
    std::mutex _mutex;
    std::condition_variable _cv;
    bool _event = false;
};

int main()
{
    EventClass object;

    std::mutex cv_mutex;
    std::condition_variable may_set_cv;
    bool may_set_event = false;

    auto setting_thread = std::thread([&]{
        std::unique_lock<std::mutex> lock { cv_mutex };
        may_set_cv.wait(lock,
                        [&] {
                            return may_set_event;
                        });
        object.SetEvent();
    });
    std::unique_lock<std::mutex> lock { cv_mutex };
    may_set_event = true;
    lock.unlock();
    may_set_cv.notify_one();

    // tiny race condition here

    object.WaitForEvent();

    setting_thread.join();
}

Upvotes: 1

Related Questions