C++11 sleep_ 函数有奇怪的行为

标签 c++ gcc c++11

Here它说sleep_for “阻止当前线程的执行至少指定的 sleep_duration。”

Here它说sleep_until “阻止当前线程的执行直到达到指定的 sleep_time 已达到。”

因此,考虑到这一点,我只是在做我的事情,直到我注意到我的代码的 sleep 时间比指定的时间短得多。为了确保 sleep_ 代码很奇怪,而不是我再次编写愚蠢的代码,我创建了这个在线示例:https://ideone.com/9a9MrC (编辑行下方的代码块)运行在线示例时,它完全执行了它应该执行的操作,但是在我的计算机上运行完全相同的代码示例会给出以下输出:Output on Pastebin

现在我真的很困惑,想知道我的机器上的哔声出了什么问题。我在 Win7 x64 机器上使用 Code::Blocks 作为 IDE 并结合 This包含 GCC 4.8.2 的工具链。

*我已经尝试过This当前工具链之前的工具链,但奇怪的是,这个带有 GCC 4.8.0 的工具链甚至无法编译示例代码。

什么会造成这种奇怪的行为?我的机器? window ?海湾合作委员会?工具链中还有其他东西吗?

附:该示例在 Here 上也能正常工作。 ,其中声明它使用 GCC 版本 4.7.2

p.p.s。使用#include <windows.h>Sleep( 1 );在我的机器上, sleep 时间也比指定的 1 毫秒短得多。

编辑:示例中的代码:

#include <iostream>         // std::cout, std::fixed
#include <iomanip>          // std::setprecision
//#include <string>           // std::string
#include <chrono> // C++11  // std::chrono::steady_clock
#include <thread> // C++11  // std::this_thread

std::chrono::steady_clock timer;
auto startTime = timer.now();
auto endTime = timer.now();
auto sleepUntilTime = timer.now();

int main() {

for( int i = 0; i < 10; ++i ) {
    startTime = timer.now();
    sleepUntilTime = startTime + std::chrono::nanoseconds( 1000000 );
    std::this_thread::sleep_until( sleepUntilTime );
    endTime = timer.now();
    std::cout << "Start time: " << std::chrono::duration_cast<std::chrono::nanoseconds>( startTime.time_since_epoch() ).count() << "\n";
    std::cout << "End   time: " << std::chrono::duration_cast<std::chrono::nanoseconds>( endTime.time_since_epoch() ).count() << "\n";
    std::cout << "Sleep till: " << std::chrono::duration_cast<std::chrono::nanoseconds>( sleepUntilTime.time_since_epoch() ).count() << "\n";

    std::cout << "It took: " << std::chrono::duration_cast<std::chrono::nanoseconds>( endTime - startTime ).count() << " nanoseconds. \n";
    std::streamsize prec = std::cout.precision();
    std::cout << std::fixed << std::setprecision(9);
    std::cout << "It took: " << ( (float) std::chrono::duration_cast<std::chrono::nanoseconds>( endTime - startTime ).count() / 1000000 ) << " milliseconds. \n";
    std::cout << std::setprecision( prec );
}
std::cout << "\n\n";
for( int i = 0; i < 10; ++i ) {
    startTime = timer.now();
    std::this_thread::sleep_for( std::chrono::nanoseconds( 1000000 ) );
    endTime = timer.now();
    std::cout << "Start time: " << std::chrono::duration_cast<std::chrono::nanoseconds>( startTime.time_since_epoch() ).count() << "\n";
    std::cout << "End   time: " << std::chrono::duration_cast<std::chrono::nanoseconds>( endTime.time_since_epoch() ).count() << "\n";

    std::cout << "It took: " << std::chrono::duration_cast<std::chrono::nanoseconds>( endTime - startTime ).count() << " nanoseconds. \n";
    std::streamsize prec = std::cout.precision();
    std::cout << std::fixed << std::setprecision(9);
    std::cout << "It took: " << ( (float) std::chrono::duration_cast<std::chrono::nanoseconds>( endTime - startTime ).count() / 1000000 ) << " milliseconds. \n";
    std::cout << std::setprecision( prec );
}

return 0;
}

最佳答案

您的机器没有任何问题,只是您的假设错误。

sleep 是一件非常依赖系统且不可靠的事情。一般来说,在大多数操作系统上,您或多或少可以保证 sleep 调用将延迟执行至少您要求的时间。 C++ 线程库必然使用操作系统提供的设施,因此您引用了 C++ 标准中的措辞。

您会注意到上一段中的“或多或少保证”一词。首先, sleep 的运作方式并不像你想象的那样。它通常不会阻塞,直到计时器触发然后恢复执行。相反,它只是将线程标记为“未就绪”,并另外执行一些操作,以便稍后可以撤消(这到底是什么未定义,它可能正在设置计时器或其他内容)。
当时间到了,操作系统会再次将线程设置为“准备运行”。这并不意味着它会运行,它只意味着只要操作系统受到干扰并且 CPU 核心空闲(并且没有更高优先级的人想要它),它就可以运行。

在传统的非无滴答操作系统上,这意味着线程将可能(或更准确地说,可能)在下一个调度程序滴答处运行。也就是说,如果 CPU 完全可用。在更现代的“无滴答”操作系统(Linux 3.x 或 Windows 8)上,您更接近现实,但仍然没有任何硬性保证。

此外,在类 Unix 系统下,sleep 可能会被信号中断,并且实际上等待的时间可能会少于指定的时间。另外,在 Windows 下,调度程序运行的时间间隔是可配置的,更糟糕​​的是,不同的 Windows 版本的行为不同 [1] [2]关于他们是否将 sleep 时间向上或向下舍入。
您的系统(Windows 7)向下舍入,所以确实是的,您实际上等待的时间可能比您预期的要短。

tl;博士

sleep 是不可靠的,只是一个非常粗略的“提示”(不是必需的),您希望将控制权传回操作系统一段时间

关于C++11 sleep_ 函数有奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22863545/

相关文章:

c++ - 为什么不能将模板函数作为模板模板参数传递?

c++ - 警告 : System. Web.dll 构建时没有依赖于 : System. Web.Services.dll Mono.Web.dll 的部分

c++ - 没有类类型 C++

c++ - 嵌套在函数调用中的 initializer_lists 中的临时对象的生命周期

c++ - 使用模板特化

c++ - 如何将 SQLite C++ 库添加到 Eclipse(C++ 版本)

c - 从 C 代码构建 AST

c++ - 模板继承自模板,但编译器提示未从基本模板声明标识符

ubuntu - 如何使用 libcurl 和 C : 从 IMAP 服务器读取消息

c++ - boost std unique_ptr 的 STL 集合的序列化