0

Consider a predicate that checks for flags updated outside of a condition variable mutex lock (since I want to abstract away from the wait implementation). Would adding an empty lock scope before notifying the condition variable prevent lost notifications? Here is a minimal example.

#include <condition_variable>
#include <mutex>
#include <atomic>
#include <functional>
#include <thread>

class TaskScheduler {
public:
    static void someMethod(std::function<bool(void)>&& pred) {
        _wait(std::move(pred));
    }

    static void notify() {
        {
            std::lock_guard<std::mutex> lock(waitMutex);
        }
        waitCV.notify_all();
    }
private:
    static std::mutex waitMutex;
    static std::condition_variable waitCV;

    static void _wait(std::function<bool(void)>&& pred) {
        std::unique_lock<std::mutex> lock(waitMutex);
        waitCV.wait(lock, [&](){return pred();});
    } 

};

std::mutex TaskScheduler::waitMutex;
std::condition_variable TaskScheduler::waitCV;

std::atomic<bool> waiting{false};
std::atomic<bool> atomicFlag{false};
void thread1() {
    TaskScheduler::someMethod([&](){waiting = true; return atomicFlag.load();});
}

void thread2() {
     // this is called while thread1 is waiting
     atomicFlag = true;
     TaskScheduler::notify();
}

int main(int argc, char **argv) {
     std::thread th1([&](){thread1();});
     while (!waiting) {};
     std::thread th2([&](){thread2();});
     th2.join();
     th1.join();
}
  • Is that code, or pseudocode? Because that looks like real code at first glance. –  Jul 09 '19 at 12:18
  • What are you asking? – nada Jul 09 '19 at 12:21
  • @TedLyngmo added a minimal example + made myself clearer –  Jul 09 '19 at 13:53
  • @codejunkiie Much better! "_Would adding an empty lock scope before notifying the condition variable prevent lost notifications?_" - I don't think the `lock_guard` in `notify()` will have any other effect than affecting timing slightly. _If_ it does seem to have an affect, my guess is that there's a logic error somewhere. If you want to hide mutexes and condition variables, perhaps you could make it a TaskQueue where users can put and pick tasks and hide all the mutex/locking/notifying stuff completely hidden inside the queue itself? – Ted Lyngmo Jul 09 '19 at 14:49
  • @TedLyngmo The implementation I'm trying to achieve is a black box task scheduler with its own exclusively managed threads. From any thread you can schedule tasks or alter the state of this scheduler (start, stop, destroy,...). If the task scheduler is at that current moment busy, when signalling to destroy you can decided to wait up to a certain timeout period or until some application scoped flags are set (e.g. continue to wait unless this thread has to kill itself then it should immediately abort. The thread which is in the process of waiting could be a completely separate entity). –  Jul 09 '19 at 15:11
  • @TedLyngmo what I understand from the standard is that the lock is held by the condition variable when it's not waiting / polling for notifications - so I thought that if I were to acquire the lock before notifying, that would enforce the cv to go into wait mode which would then mean it could catch the notification or spuriously wake-up (in any case the flags have certainly been update so pred() should be evaluated correctly). –  Jul 09 '19 at 15:15
  • "_I thought that if I were to acquire the lock before notifying, that would enforce the cv to go into wait mode_" No, not unless there's something I've totally misunderstood. The waiting side will only go into waiting if the predicate is false: `while( !Pred() ) cv.wait(lock);`. Also, now you just acquire the lock and then release it directly.. A blockbox sounds ideal. Perhaps you can separate it further to have a generic message queue, only concerned about passing messages safely between producers and consumers. Adding a thread pool on top of that will be a piece of cake. – Ted Lyngmo Jul 09 '19 at 16:11
  • 1
    The answer to this question might help... https://stackoverflow.com/questions/48958530/should-condition-variable-notify-all-be-covered-by-mutex-lock – ttemple Jul 09 '19 at 20:00
  • @ttemple Doubtful. The question here is about adding a lock-unlock that doesn't guard anything vs. having no lock at all. The notify call is not guarded in any of the cases. – Ted Lyngmo Jul 10 '19 at 05:44
  • @ttemple I think that answers my question precisely, thank you! –  Jul 11 '19 at 11:31

0 Answers0