我想测量一个条件变量通知另一个等待的线程需要多长时间。我写了这个例子来尝试捕捉时间差:
bool ready{false};
mutex m;
condition_variable cv;
decltype(chrono::steady_clock::now()) t1;
decltype(chrono::steady_clock::now()) t2;
void notifying_thread() {
{
lock_guard<mutex> lg{m};
ready = true;
}
t1 = chrono::steady_clock::now();
cv.notify_one();
}
void waiting_thread() {
unique_lock<mutex> ul{m};
cv.wait(ul, [] { return ready; });
t2 = chrono::steady_clock::now();
}
int main() {
auto f1{async(notifying_thread)};
auto f2{async(waiting_thread)};
f1.get();
f2.get();
cout << chrono::duration_cast<chrono::microseconds>(t2 - t1).count() << " µs\n";
return 0;
}
字符串
我做得对吗?我的chrono::steady_clock::now()
s是否在正确的位置?平均时间约为25 µs,但有时甚至是负数。它怎么可能是负数?t1
不应该总是在t2
之前启动吗?async
的启动策略是否相关?
1条答案
按热度按时间zrfyljdw1#
你的推理中缺少了虚假的唤醒。
字符串
wait(lock)
可以返回,即使条件变量没有被通知。这就是 predicate 的作用。当有伪唤醒时,你会一直循环,直到条件被满足。由于虚假唤醒,
wait(lock)
可能会在另一个线程notify_one
之前解除阻塞,但在它设置ready = true
之后。在这种情况下,t2
可能比t1
早。此外,正如DanielLangr在评论中指出的那样,当条件在进入上述循环之前已经被填满时,
wait(lock)
永远不会被调用。同样在这种情况下,t2
可以早于t1
。此外,这两个线程并不是立即启动的,如果
notifying_thread
启动,而waiting_thread
启动的时间要晚一些,那么你基本上是在测量这个时间,而不是通知条件变量所花费的时间。