Consider the following codesnippet:
#include <iostream>
#include <condition_variable>
#include <chrono>
#include <mutex>
int main () {
std::mutex y;
std::condition_variable x;
std::unique_lock<std::mutex>lock{y};
int i = 0;
auto increment = [&] {++i; return false;};
using namespace std::chrono_literals;
//lock 5s if increment returns false
//let's see how often was increment called?
x.wait_for(lock, 5s, increment);
std::cout << i << std::endl;
//compare this with a simple loop:
//how often can my system call increment in 5s?
auto const end = std::chrono::system_clock::now() + 5s;
i = 0;
while (std::chrono::system_clock::now() < end) {
increment();
}
std::cout << i;
}
As I understand wait_for, i
should be O(1) after wait_for
(let's assume spurious unlocks are rare).
However, I get
i ~= 3e8
for kernel 4.17.14, Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
,
i ~= 8e6
for kernel 3.10.0, Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz
.
This sounds funny, so i check by comparing with a simple loop that runs 5 seconds. Roughly same results for i
, only a 5-10% difference.
Question:
what is wait_for
doing? Does it work as expected and I just understood cppreference wrong, or did I mess up?
Second, (optional) question: Where does this enormous difference in i
come from?
Additional info:
(gcc7.3
, gcc8.2
, clang6.0
), flags: -O3 --std=c++17
all yield comparable results.
2
for every version of clang and gcc I've tried forx.wait_for(lock, 5s, increment); std::cout << i << std::endl;
. I also get3
on my local machine with MSVS. – AnnadianeEINTR
which could be handled transparently, but is deliberately not, in order to allow the program to deal with signals more easily), and a scenario where a thread starts to wait just as another thread is currently being woken up (i.e. requiring at least two waiters). In the latter case, it is or was possible that both threads continue as the result of just one call topthread_cond_signal
. I don't even know if this still applies to the current implementation, though. – Timecard