提问人:user3100212 提问时间:11/10/2023 最后编辑:HolyBlackCatuser3100212 更新时间:11/10/2023 访问量:118
一个线程通知另一个线程需要多长时间?
How long does it take for one thread to notify another thread?
问:
我想测量条件变量通知另一个等待线程所需的时间。我写了这个例子来尝试捕捉时差:
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;
}
我做对了吗?我把我的 s 放在正确的地方吗?平均时间为~25 μs,但有时甚至是负数。怎么可能是负面的?不应该总是在之前开始吗?发布政策是否相关?chrono::steady_clock::now()
t1
t2
async
答:
3赞
463035818_is_not_an_ai
11/10/2023
#1
你的推理中缺少虚假的觉醒。带有谓词的 std::condition_variable::wait
重载等效于
while (!stop_waiting())
{
wait(lock);
}
wait(lock)
即使未通知条件变量,也可以返回。这就是谓词的用途。当有虚假唤醒时,你会继续循环,直到条件被满足。
由于虚假唤醒,可能会发生在其他线程调用之前但在设置之后解锁的情况。在这种情况下,可以早于 .wait(lock)
notify_one
ready = true
t2
t1
此外,正如 DanielLangr 在评论中指出的那样,当条件在进入上述循环之前就已经完全填充时,则永远不会被调用。同样在这种情况下,可以早于 .wait(lock)
t2
t1
此外,这两个线程不会立即启动。如果开始和开始的时间过后,那么你基本上是在测量该时间,而不是通知条件变量所需的时间。notifying_thread
waiting_thread
评论
1赞
Daniel Langr
11/10/2023
AFAIK,虚假唤醒相对罕见。但在这里,也可能发生的情况是,在到达循环之前先设置标志。因此,根本不是调用。如果发生这种情况,这些时间测量值将完全不同步。ready
while
wait
1赞
463035818_is_not_an_ai
11/10/2023
@DanielLangr好点子。我过于关注一个反例,而错过了一个更明显的反例
上一个:从头文件移动第三方库
下一个:C++ 中的二维数组初始化11
评论
notify_one
ready = true;
cv.notify_one();
notifying_thread
waiting_thread
t1
t2
t2
t1
wait
ready
t1 = chrono::steady_clock::now(); cv.notify_one();
t2
cannot be set until afterwait
returnstrue
” — 您错过了 (1) 未在 (2) 中调用的可能情况,甚至没有调用一次。有关详细信息,请参阅答案。wait
wait