Linux中的sleep、usleep、nanosleep、poll和select

一見發表於2019-01-25

在進行Linux C/C++程式設計時,可呼叫的sleep函式有好多個,那麼究竟應當呼叫哪一個了?下表列出了這幾個函式間的異同點,可作為參考:

 

性質

精準度

執行緒安全

訊號安全

 

sleep

libc庫函式

不能和alarm同時使用

有些是基於alarm實現的,所以不能和alarm同時使用

usleep

libc庫函式

微秒

-

-

POSIX.1-2001已將usleep標註為廢棄,POSIX.1-2008已刪除usleep,應當使用nanosleep替代usleep

nanosleep

系統呼叫

納秒

不確定

即使被訊號中斷,也可實現實際睡眠時長不小於引數指定時長

clock_nanosleep

系統呼叫

納秒

不確定

區別於nanosleep,可選擇為相對或絕對時間,其次是可以選擇使用哪個時鐘

poll

系統呼叫

毫秒

在協程庫libco中可安全使用,如被訊號中斷,則實際睡眠時長會小於引數指定的時長

ppoll

系統呼叫

納秒

如被訊號中斷,則實際睡眠時長會小於引數指定的時長

select

系統呼叫

微秒

即使被訊號中斷,也可實現實際睡眠時長不小於引數指定時長

pselect

系統呼叫

納秒

如被訊號中斷,則實際睡眠時長會小於引數指定的時長

 

C/C++常用封裝:

1) 基於nanosleep的毫秒級封裝

#include <time.h>

void millisleep(uint32_t milliseconds) {

    struct timespec ts = {

        milliseconds / 1000,

        (milliseconds % 1000) * 1000000

    };

    while ((-1 == nanosleep(&ts, &ts)) && (EINTR == errno));

}

 

2) 基於nanosleep的微秒級封裝

#include <time.h>

void microsleep(uint32_t microseconds) {

    struct timespec ts = {

        microseconds / 1000000,

        (microseconds % 1000000) * 1000

    };

    while ((-1 == nanosleep(&ts, &ts)) && (EINTR == errno));

}

 

3) 基於poll的秒級封裝

// 可libco協程庫中安全使用

void pollsleep(int milliseconds) {

    (void)poll(NULL, 0, milliseconds);

}

 

4) 基於select的毫秒級封裝

void selectsleep(int milliseconds) {

    struct timeval timeout = {

        milliseconds / 1000,

        (milliseconds % 1000)

    };

    struct timeval old_timeout = { timeout.tv_sec, timeout.tv_usec };

    while (true) {

        (void)select(0, NULL, NULL, NULL, &timeout);

        if (timeout.tv_sec<=0 && timeout.tv_usec<=0)

            break;

    }

}

 

如果開發環境是C++11或更高版本,則可直接使用C++標準庫提供的:

5) 毫秒睡眠

#if __cplusplus >= 201103L

#include <chrono>

#include <system_error>

#include <thread>

 

std::this_thread::sleep_for(std::chrono::milliseconds(1000));

#endif // __cplusplus >= 201103L

 

6) 微秒睡眠

#if __cplusplus >= 201103L

#include <chrono>

#include <system_error>

#include <thread>

 

std::this_thread::sleep_for(std::chrono::microseconds(1000));

#endif // __cplusplus >= 201103L

 

上述介紹的sleep函式均不方便控制它們提前結束,如果需要這種sleep,可基於pthread_cond_timedwait實現,實現可參考CEvent原始碼:

https://github.com/eyjian/libmooon/blob/master/src/sys/event.cpp

 

相關文章