四时宝库

程序员的知识宝库

c++ 疑难杂症(15) 关于sleep(c++11 sleep_for)

c++11开始 STL 提供了 sleep_for 及 sleep_until 用于休眠, 来理理。

1. 文档

1.1 std::this_thread::sleep_for

//(c++11起)
//include <thread>
template< class Rep, class Period > 
void sleep_for( const std::chrono::duration );

阻塞当前线程执行,至少经过指定的 sleep_duration

此函数可能阻塞长于 sleep_duration ,因为调度或资源争议延迟。

标准库建议用稳定时钟度量时长。若实现用系统时间代替,则等待时间亦可能对时钟调节敏感。

参数

sleep_duration 要睡眠的时长

异常

任何时钟、 time_point 或 duration 在执行间抛出的异常(标准库提供的时钟、时间点和时长决不抛出)。

示例

#include <iostream>
#include <chrono>
#include <thread>
 
int main()
{
    using namespace std::chrono_literals;
    std::cout << "Hello waiter\n" << std::flush;
    auto start = std::chrono::high_resolution_clock::now();
    std::this_thread::sleep_for(2000ms);
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end-start;
    std::cout << "Waited " << elapsed.count() << " ms\n";
}

可能的输出:

Hello waiter
Waited 2000.12 ms

1.2 std::this_thread::sleep_until

//(c++11起)
//include <thread>
template< class Clock, class Duration > 
void sleep_until( const std::chrono::time_point<Clock,Duration>& sleep_time );

阻塞当前线程,直至抵达指定的 sleep_time

Clock 必须符合时钟 (Clock) 要求。如果 std::chrono::is_clock_v<Clock> 是 false,那么程序非良构。 (C++20 起)

标准推荐使用绑定到 sleep_time 的时钟,此时调整时钟会有影响。从而阻塞的时长可能会小于或大于调用时的 sleep_time - Clock::now(),取决于调整的方向以及实现是否尊重这样的调整。函数也可能会因为调度或资源纠纷延迟而阻塞到 sleep_time 之后的某个时间点。

参数

sleep_time 要阻塞到的时间

异常

任何 ClockDuration 可能抛出的异常(标准库提供的时钟和时长决不抛出)

示例

#include <iostream>  
#include <chrono>  
#include <thread>  
  
int main() {  
    // 获取当前时间点  
    auto now = std::chrono::system_clock::now();  
  
    // 设置线程休眠到未来的某个时间点,例如5秒后  
    auto five_seconds_future = now + std::chrono::seconds(5);  
  
    // 使线程休眠直到指定的时间点  
    std::this_thread::sleep_until(five_seconds_future);  
  
    // 当线程醒来后,输出消息  
    std::cout << "Woke up after 5 seconds!" << std::endl;  
  
    return 0;  
}

输出:

Woke up after 5 seconds!

1.3 系统 API

1.3.1 Linux

  • usleep
#include <unistd.h> 
usleep(unsigned int usecs);

使调用线程睡眠指定的微秒数。这个函数是UNIX和Linux中传统的延迟方法,但由于其精度问题,现在通常被更精确的函数所替代。

  • nanosleep
#include <time.h> int nanosleep(const struct timespec *req, struct timespec *rem);

提供了纳秒级的精度,允许你指定一个timespec结构来表示要睡眠的时间。

  • clock_nanosleep
#include <time.h> 
int clock_nanosleep(clockid_t clock_id, int flags, 
const struct timespec *req, 
struct timespec *rem);

允许你基于特定的时钟(如实时时钟或单调时钟)进行睡眠。它提供了更高的精度和灵活性。

1.3.2 Windows

  • Sleep
#include <windows.h> 
void Sleep(DWORD dwMilliseconds);

它使当前线程暂停执行指定的毫秒数。

  • SleepEx
DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable);

SleepEx是Sleep的扩展版本,它提供了更多的选项,比如允许线程在休眠期间接收信号。

2. 实现

  • linux gcc


  • windows vs2022

_Thrd_sleep没有找到相应的说明。

测试现象:如果在休眠时,把系统时间向回调10分钟,那么它会相应的卡在_Thrd_sleep里面多10分钟, 与设想的不一样(小心!!!)。

  • 总结:

通过上面的文档及源码可知:

多使用sleep_for, 少使用sleep_until。

不要一次休眠太长时间, 如:要休眠120秒, 那么可以换成休眠120次, 每次休眠1秒。

尽量避免因调整系统时间引起问题。

示例

#include <iostream>
#include <thread>
#include <chrono>

int main()
{
    std::cout << "go to sleep" << std::endl;

    std::thread([]() {
        
        std::cout << "std::this_thread::sleep_for" << std::endl;
        auto sec = std::chrono::seconds(3);
        std::this_thread::sleep_for(sec);
    }).join();

    std::thread([]() {

        std::cout << "std::this_thread::sleep_until" << std::endl;
        auto now = std::chrono::system_clock::now();
        now +=  std::chrono::seconds(3);
        std::this_thread::sleep_until(now);
    }).join();

    std::cout << "all wakeup" << std::endl;
    return 0;
}






发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接