|
Boost Users : |
Subject: [Boost-users] [Thread] thousands of spurious wakeups from timed_wait() per second
From: Steven Clark (steven.clark_at_[hidden])
Date: 2014-09-09 22:38:14
I've been trying to get useful behavior out of
condition_variable::timed_wait() with little success. Depending on
the platform, I'm getting about 3000 or nearly 100000 spurious wakeups
per second.
I'm working on a few different Linux platforms with different versions
of Boost: 1.46, 1.48, and another in the high 40's. The eventual target
is 1.48. I've looked for bug reports and haven't found any, and I have
no evidence yet that suggests the different versions are significant to
this problem.
Because of the lack of problem reports, I figure I'm doing something
wrong. That's my question: "What am I doing wrong here?"
I have a test program that sets up a typical producer/consumer example.
The main program spawns a thread, the producer, that notifies the main
thread via a condition_variable once a second for a few seconds, then
ends. The main thread, the consumer, waits efficiently for notifications
with a 2-second timeout. When the producer thread finishes, the main
(consumer) thread eventually times out, joins the spawned thread,
and exits. At least, that's what is supposed to happen.
If I don't bother with timeouts and use condition_variable::wait(), it
works perfectly - except for the timeout, join, and exit. This is as
expected. So far I have seen no spurious wakeups at all with this test.
There is an ominous yet ambiguous remark in the documentation
"The duration overload of timed_wait is difficult to use correctly.
The overload taking a predicate should be preferred in most cases."
Due to that remark I stopped experimenting with relative timeouts before
I got anything to work. Using absolute timeouts, I get very high numbers
of spurious wakeups as mentioned above - 3000 and about 100000 per second
depending on the platform. I see no difference between timed_wait with
a predicate and without a predicate.
I'm also having trouble with the return value of timed_wait().
The documentation carefully states that timed_wait() returns "false if
the call is returning because the time specified by abs_time was reached,
true otherwise". This seems to mean that spurious wakeups return true
-- and if you think about it, the return value is useless if spurious
wakeups could return false. You'd have to add your own check for timeout.
I was quite surprised to find that every spurious wakeup of timed_wait()
that I've ever seen returns false. That just doesn't make sense to me.
Here is the version of my test program that uses timed_wait without a
predicate, followed by its output.
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <iostream>
boost::condition_variable gCond;
boost::mutex gMutex;
bool gGotData;
unsigned gValue;
void threadfn() {
for (unsigned i = 0; i < 7; i++) {
std::cerr << "hello from threadfn(), #" << i << std::endl;
{
boost::lock_guard<boost::mutex> guard(gMutex);
gGotData = true;
gValue = i;
}
gCond.notify_one();
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
}
int main() {
std::cerr << "******* Using timed_wait()" << std::endl;
gGotData = false;
gValue = 999;
boost::thread t(threadfn);
while (true) {
boost::system_time deadline(
boost::posix_time::microsec_clock::local_time());
std::cerr << "now is " << deadline << std::endl;
deadline += boost::posix_time::seconds(2);
std::cerr << "deadline is " << deadline << std::endl;
boost::unique_lock<boost::mutex> lock(gMutex);
unsigned nWakeups = 0;
while(!gGotData) {
bool ret = gCond.timed_wait(lock, deadline);
nWakeups++;
if (ret) std::cerr << "timed_wait() returned true on wakeup #"
<< nWakeups << std::endl;
}
std::cerr << "main() exited inner loop with " << nWakeups
<< " wakeups; gGotData is "
<< (gGotData ? "true" : "false") << std::endl;
if (gGotData) {
std::cerr << "main(), notified, gValue is " << gValue << std::endl;
gGotData = false;
}
}
// not reached in this incarnation of the code
t.join();
std::cerr << "main(), after joining" << std::endl;
}
******* Using timed_wait()
now is 2014-Sep-09 20:48:12.183781
deadline is 2014-Sep-09 20:48:14.183781
hello from threadfn(), #0
timed_wait() returned true on wakeup #1451
main() exited inner loop with 1451 wakeups; gGotData is true
main(), notified, gValue is 0
now is 2014-Sep-09 20:48:12.215471
deadline is 2014-Sep-09 20:48:14.215471
hello from threadfn(), #1
timed_wait() returned true on wakeup #96864
main() exited inner loop with 96864 wakeups; gGotData is true
main(), notified, gValue is 1
now is 2014-Sep-09 20:48:13.216511
deadline is 2014-Sep-09 20:48:15.216511
hello from threadfn(), #2
timed_wait() returned true on wakeup #95911
main() exited inner loop with 95911 wakeups; gGotData is true
main(), notified, gValue is 2
now is 2014-Sep-09 20:48:14.216805
deadline is 2014-Sep-09 20:48:16.216805
hello from threadfn(), #3
timed_wait() returned true on wakeup #97526
main() exited inner loop with 97526 wakeups; gGotData is true
main(), notified, gValue is 3
now is 2014-Sep-09 20:48:15.217191
deadline is 2014-Sep-09 20:48:17.217191
hello from threadfn(), #4
timed_wait() returned true on wakeup #104710
main() exited inner loop with 104710 wakeups; gGotData is true
main(), notified, gValue is 4
now is 2014-Sep-09 20:48:16.217453
deadline is 2014-Sep-09 20:48:18.217453
hello from threadfn(), #5
timed_wait() returned true on wakeup #102404
main() exited inner loop with 102404 wakeups; gGotData is true
main(), notified, gValue is 5
now is 2014-Sep-09 20:48:17.217685
deadline is 2014-Sep-09 20:48:19.217685
hello from threadfn(), #6
timed_wait() returned true on wakeup #97906
main() exited inner loop with 97906 wakeups; gGotData is true
main(), notified, gValue is 6
now is 2014-Sep-09 20:48:18.217291
deadline is 2014-Sep-09 20:48:20.217291
^C
Thank you very much,
Steven Clark
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net