gpt4 book ai didi

C++11 线程等待行为:std::this_thread::yield() 与 std::this_thread::sleep_for( std::chrono::milliseconds(1) )

转载 作者:IT老高 更新时间:2023-10-28 12:39:09 25 4
gpt4 key购买 nike

我在编写 Microsoft 特定的 C++ 代码时被告知要编写 Sleep(1)在自旋锁定方面比 Sleep(0) 好得多,因为 Sleep(0) 将使用更多的 CPU 时间,而且,它只有在有另一个同等优先级线程等待运行。

但是,对于 C++11 线程库,没有太多关于 std::this_thread::yield() 效果的文档(至少我能够找到) vs. std::this_thread::sleep_for(std::chrono::milliseconds(1));第二个肯定更冗长,但它们对于自旋锁是否同样有效,或者它是否受到影响 Sleep(0)Sleep(1) ?

一个示例循环,其中 std::this_thread::yield()std::this_thread::sleep_for( std::chrono::milliseconds(1) ) 可以接受:

void SpinLock( const bool& bSomeCondition )
{
// Wait for some condition to be satisfied
while( !bSomeCondition )
{
/*Either std::this_thread::yield() or
std::this_thread::sleep_for( std::chrono::milliseconds(1) )
is acceptable here.*/
}

// Do something!
}

最佳答案

这里的标准有些模糊,因为具体的实现很大程度上会受到底层操作系统调度能力的影响。

话虽如此,您可以放心地假设任何现代操作系统上的一些事情:

  • yield 将放弃当前的时间片并将线程重新插入调度队列。在线程再次执行之前到期的时间量通常完全取决于调度程序。请注意,标准将产量称为重新安排的机会。因此,如果需要,实现可以完全自由地立即从 yield 中返回。 yield 永远不会将线程标记为非事件状态,因此在 yield 上旋转的线程将始终在一个内核上产生 100% 的负载。如果没有其他线程准备好,您最多可能会丢失当前时间片的剩余部分,然后再重新安排。
  • sleep_* 将至少在请求的时间内阻塞线程。一个实现可以将 sleep_for(0) 变成 yield。另一方面, sleep_for(1) 将使您的线程暂停。该线程不是返回调度队列,而是首先进入另一个 sleep 线程队列。只有在请求的时间量过去后,调度程序才会考虑将线程重新插入调度队列。小 sleep 产生的负载仍然会非常高。如果请求的休眠时间小于系统时间片,可以预期线程只会跳过一个时间片(即一个yield释放事件时间片,然后跳过一个),这仍然会导致cpu负载在一个核心上接近甚至等于 100%。

关于哪个更适合自旋锁定的几句话。当对锁几乎没有争用时,自旋锁是一种选择的工具。如果在绝大多数情况下您希望锁可用,则自旋锁是一种便宜且有值(value)的解决方案。但是,一旦发生争用,自旋锁会让你付出代价。如果您担心 yield 或 sleep 是否是更好的解决方案,那么这里自旋锁是 错误的工作工具。您应该改用互斥锁。

对于自旋锁,您实际上必须等待锁定的情况应该被视为异常(exception)。因此,在这里直接屈服是完全没问题的——它清楚地表达了意图,浪费 CPU 时间一开始就不应该成为问题。

关于C++11 线程等待行为:std::this_thread::yield() 与 std::this_thread::sleep_for( std::chrono::milliseconds(1) ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17325888/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com