深入理解linux下的短延遲:nanosleep,sleep

最近在使用nanosleep的時(shí)候又踩坑了。于是整理下linux短延遲的用法。

用法

回顧下秒的換算:ms(毫秒),μs(微秒),ns(納秒),ps(皮秒)
1s = 1000ms = 1000 * 1000us = 1000 * 1000 * 1000ns = 1000 * 1000 * 1000* 1000ps

sleep()-------以秒為單位
#include<unistd.h>
unsigned int sleep(unsigned int seconds);
return:若進(jìn)程暫停到參數(shù)seconds 所指定的時(shí)間,成功則返回0,若有信號(hào)中斷則返回剩余秒數(shù)。
在linux中,sleep是通過nanosleep實(shí)現(xiàn)的。在一些其他系統(tǒng)中(例如POSIX.1),它是通過alarm()來實(shí)現(xiàn)的。

usleep()----以微秒為單位
#include<unistd.h>
unsigned int usleep(unsigned int useconds);
return:若進(jìn)程暫停到參數(shù)seconds 所指定的時(shí)間,成功則返回0,若有信號(hào)中斷則返回剩余微秒數(shù)。

nanosleep( )---------以納秒為單位
#include<time.h>
 struct timespec
{
  time_t  tv_sec;         /* 秒seconds */
  long    tv_nsec;        /* 納秒nanoseconds */
};
int nanosleep(const struct timespec *req, struct timespec *rem);
return: 若進(jìn)程暫停到參數(shù)*req所指定的時(shí)間,成功則返回0,若有信號(hào)中斷則返回-1,并且將剩余微秒數(shù)記錄在*rem中。
req->tv_sec是以秒為單位,而tv_nsec以毫微秒為單位(10的-9次方秒)。
由于調(diào)用nanosleep是是進(jìn)程進(jìn)入TASK_INTERRUPTIBLE,這種狀態(tài)是會(huì)相應(yīng)信號(hào)而進(jìn)入TASK_RUNNING狀態(tài)的。

函數(shù)的精確度與時(shí)鐘的頻率有關(guān)系
我們假設(shè)時(shí)鐘中斷是10納秒一次,如果tv_sec = 0, tv_nsec = 2,那么時(shí)鐘中斷一定是在10納秒后來喚醒這個(gè)進(jìn)程的,這里我們看到任務(wù)的重新調(diào)度最少是在10納秒之上,因此此函數(shù)的精確程度與時(shí)鐘頻率有關(guān)系。
cpu的速度決定了時(shí)鐘周期; 如, 一個(gè) 50 MHz 的CPU, 一個(gè)時(shí)鐘周期的時(shí)間是 1/50000000 s(200 nsec)。

注意

使用這些函數(shù)時(shí)一定要注意判斷返回值。有時(shí)候會(huì)出現(xiàn)sleep函數(shù)被系統(tǒng)中斷的情況,導(dǎo)致結(jié)果不符合預(yù)期。
NANOSLEEP(2) BUGS

// POSIX nanosleep may be interrupted by signals.
  while (nanosleep(&ts, &ts) == -1 && errno == EINTR) {}

精確度對(duì)比

低精度情況(100000us及以上):usleep和nanosleep表現(xiàn)差不多。select和pselect表現(xiàn)較差。
高精度情況(100000us及以上):四者表現(xiàn)差不多。

            fuction  time(usec)    realtime      reduce
----------------------------------------------------
         usleep         500000     500091         91
         nanosleep      500000     500089         89
         select         500000     500540        540
         pselect        500000     500549        549
--------------------------------
         usleep         100000     100078         78
         nanosleep      100000     100110        110
         select         100000     100157        157
         pselect        100000     100149        149
--------------------------------
         usleep          50000      50091         91
         nanosleep       50000      50107        107
         select          50000      50111        111
         pselect         50000      50084         84
--------------------------------
         usleep          10000      10086         86
         nanosleep       10000      10091         91
         select          10000      10089         89
         pselect         10000      10088         88
--------------------------------
         usleep           1000       1089         89
         nanosleep        1000       1065         65
         select           1000       1065         65
         pselect          1000       1066         66
--------------------------------
         usleep            900        969         69
         nanosleep         900        974         74
         select            900        970         70
         pselect           900        980         80
--------------------------------
         usleep            500        569         69
         nanosleep         500        565         65
         select            500        569         69
         pselect           500        569         69
--------------------------------
         usleep            100        166         66
         nanosleep         100        165         65
         select            100        163         63
         pselect           100        163         63
--------------------------------
         usleep             10         73         63
         nanosleep          10         76         66
         select             10         73         63
         pselect            10         78         68
--------------------------------
         usleep              1         64         63
         nanosleep           1         66         65
         select              1         65         64
         pselect             1         63         62
--------------------------------

測(cè)試代碼:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<sys/time.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/select.h>
 
 
int main(int argc, char **argv)
{
    unsigned int nTimeTestSec = 0;
    unsigned int nTimeTest = 0;
    struct timeval tvBegin;
    struct timeval tvNow;
    int ret = 0;
    unsigned int nDelay = 0;
    struct timeval tv;
    int fd = 1;
    int i = 0;
    struct timespec req;
 
    unsigned int delay[20] = 
        {500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0};
    int nReduce = 0; //誤差
 
    fprintf(stderr, "%19s%12s%12s%12s\n", "fuction", "time(usec)", "realtime", "reduce");
    fprintf(stderr, "----------------------------------------------------\n");
    for (i = 0; i < 20; i++)
    {
        if (delay[i] <= 0)
            break;
        nDelay = delay[i];
        //test sleep
        gettimeofday(&tvBegin, NULL);
        ret = usleep(nDelay);
        if(ret == -1)
        {
            fprintf(stderr, "usleep error, errno=%d [%s]\n", errno, strerror(errno));
        }
        gettimeofday(&tvNow, NULL);
        nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
        nReduce = nTimeTest - nDelay;
 
         fprintf (stderr, "\t usleep       %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
 
         //test nanosleep
         req.tv_sec = nDelay/1000000;
         req.tv_nsec = (nDelay%1000000) * 1000;
 
         gettimeofday(&tvBegin, NULL);
         ret = nanosleep(&req, NULL);
         if (-1 == ret)
         {
            fprintf (stderr, "\t nanousleep   %8u   not support\n", nDelay);
         }
         gettimeofday(&tvNow, NULL);
         nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
         nReduce = nTimeTest - nDelay;
         fprintf (stderr, "\t nanosleep    %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
 
         //test select
         tv.tv_sec = 0;
         tv.tv_usec = nDelay;
 
         gettimeofday(&tvBegin, NULL);
         ret = select(0, NULL, NULL, NULL, &tv);
         if (-1 == ret)
         {
            fprintf(stderr, "select error. errno = %d [%s]\n", errno, strerror(errno));
         }
 
         gettimeofday(&tvNow, NULL);
         nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
         nReduce = nTimeTest - nDelay;
         fprintf (stderr, "\t select       %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
 
         //pselcet
         req.tv_sec = nDelay/1000000;
         req.tv_nsec = (nDelay%1000000) * 1000;
 
         gettimeofday(&tvBegin, NULL);
         ret = pselect(0, NULL, NULL, NULL, &req, NULL);
         if (-1 == ret)
         {
            fprintf(stderr, "select error. errno = %d [%s]\n", errno, strerror(errno));
         }
 
         gettimeofday(&tvNow, NULL);
         nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
         nReduce = nTimeTest - nDelay;
         fprintf (stderr, "\t pselect      %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
 
         fprintf (stderr, "--------------------------------\n");
 
    }
    
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容