I have a thread lets call it t1, that periodically sends something after x seconds. This "x seconds part" can be changed from other thread (t2). I am supposed to be able to do following from thread t1.
- wait for "x seconds" and then send something
- in between if the thread t2 sends another value of "x" , dont send but goto step 1.
I have used condition variable for this purpose with wait_for()
I want to only do a send when "x seconds" get over.
Currently I have implemented it without predicate (because I have no need for it) something like this:
auto done = wait_for(lock,x seconds);
if(done == cv_status::timeout)
{
/*perform send operation*/
}
but sometimes I see that the "sending happens" before timeout , which I suppose is due to spurious wakeup and missing predicate.
My question is how can I take care of spurious wakeup without having a predicate? should I follow another approach for this ? I dont have a need for predicate because thread t1 sleeps on a particular condition (when x is 0) and I want it(t1) to be woken up by t2 without any condition.
This is my first task working with cond variables and I am still learning CPP ,Thank you in advance.
CodePudding user response:
No, there is no way to avoid spurious wakeups without a predicate. This is what predicates are for, in the first place. The C standard explicitly permits waits to have occasional spurious wakeups, and there are no means to prevent them.
Your only options are:
Use a predicate
Don't use a predicate, but factor in the fact that you might have a spurious wakeup into your overall logic. You cannot prevent spurious wakeups, so adjust your program's logic to accomodate them.
For example: in this case your goal is to wait for some period of time. So, before waiting, see what std::chrono::steady_clock::now()
says, and calculate what it should say after the given time period elapses. Then check it again after you allegedly waited for the prescribed period of time. If it's still less than the expected timeout, compute what's left, and wait again, hoping for better luck next time. Lather, rinse, repeat.
In all cases, keep in mind that even without spurious wakeups you have very few guarantees. Even if you demand to be woken up after exactly five seconds, it may take a little bit of time before wait_for()
returns. Plan your overall logic accordingly.
CodePudding user response:
You do need a predicate because you need to distinguish spurious wakeups from legitimate wakeups.
What you can do is to add a std::atomic<bool>
which tells you if t2 sent an x update. When t2 sends an update it also sets this atomic bool. t2 uses it on wakeup to ignore spurious wakeups and then clears it.