Linunx的sleep,usleep,select,nonasleep对比与应用

Posted 北雨南萍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linunx的sleep,usleep,select,nonasleep对比与应用相关的知识,希望对你有一定的参考价值。

前言

时钟换算:

1秒(s) = 1000 毫秒(ms) = 1,000,000 微秒(μs) = 1,000,000,000 纳秒(ns) = 1,000,000,000,000 皮秒(ps)

程序挂起主要有以下几种:

sleep, usleep, select, pselect, nanosleep;

它们的精度不同,在不同的应用场景下需要不同的函数;

 

一、用法

1.1 函数名: sleep

头文件:

#include <unistd.h>  // 在gcc编译器中,使用的头文件因gcc版本的不同而不同

功  能: 执行挂起指定的秒数

语  法: unsigned sleep(unsigned seconds);

 

示例:

#include<stdio.h>

int main()

  int a;

  a=1;

  printf("hello");

  sleep(a);      

  printf("world"); 

  return 0;

 

1.2 函数名: usleep

功  能: usleep功能把进程挂起一段时间, 单位是微秒(百万分之一秒);

头文件: #include <unistd.h>

语  法:

void usleep(int micro_seconds);

返回值: 无

内容说明:本函数可暂时使程序停止执行。参数 micro_seconds 为要暂停的微秒数(us)。

注 意:

用在Linux的测试环境下面。

参 见:usleep() 与sleep()类似,用于延迟挂起进程。进程被挂起放到reday queue。

是一般情况下,延迟时间数量级是秒的时候,尽可能使用sleep()函数。

如果延迟时间为几十毫秒(1ms = 1000us),或者更小,尽可能使用usleep()函数。这样才能最佳的利用CPU时间.

 

1.3 函数名:select

功能:I/O多工机制

用来等待文件描述符状态的改变。

头文件:

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

语法:

int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval*timeout);

参数说明:

maxfdp: 最大的文件描述符加1,如果我有三个文件节点1、4、6,那第一个参数就为7(6+1)

readfds: 可读文件节点集,类型为fd_set。

通过FD_ZERO(&readfd);初始化节点集;

然后通过FD_SET(fd, &readfd);把需要监听是否可读的节点加入节点集

readfds: 可写文件节点集中,类型为fd_set。操作方法和第二个参数一样。

errorfds: 检查节点错误集。

timeout: 超时参数,类型为struct timeval,用于设置超时时间,

分别可设置秒timeout.tv_sec和微秒timeout.tv_usec。

返回值:

执行成功则返回文件描述符状态已经改变的个数,

如果返回0,则表示在描述符在状态改变前已经超过了timeout时间。

当有错误发生时,返回-1, 且错误原因保存在errno中。

 

定时器用法:

//test

select tv.tv_sec = 0;

tv.tv_usec = 500000;

ret = select(0, NULL, NULL, NULL, &tv);

if (-1 == ret)

    fprintf(stderr, "select error. errno = %d [%s]\\n", errno, strerror(errno));

 

1.4 函数名:pselect

功能:I/O多工机制

头文件:

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <sys/select.h>

语法:

int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timespec* timeout,

const sigset_t *sigmask);

说明:

pselect()和select()作用几乎一样,都是用来等待文件描述符状态的改变,

不过pselect() 还可以判断是否有信号(signal)发生。

 

定时器用法:

req.tv_sec = nDelay/1000000;

req.tv_nsec = (nDelay%1000000) * 1000;

ret = pselect(0, NULL, NULL, NULL, &req, NULL);

if (-1 == ret)

fprintf(stderr, "select error. errno = %d [%s]\\n", errno, strerror(errno));

 

1.5 函数名:nonasleep

功能:

nanosleep()函数会导致当前的线程将暂停执行,直到rqtp参数所指定的时间间隔。

或者在指定时间间隔内有信号传递到当前线程,将引起当前线程调用信号捕获函数或终止该线程。

 

头文件:

#include<time.h>

#include<sys/time.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/select.h>

 

语法:

  int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

 

描述:

nanosleep()函数会导致当前的线程将暂停执行,直到rqtp参数所指定的时间间隔。

或者在指定时间间隔内有信号传递到当前线程,将引起当前线程调用信号捕获函数或终止该线程。

  暂停时间可能超过请求时间,因为参数值是sleep粒度的整数倍数或者因为其他活动的系统调度。

  但是,除了被信号中断的情况下,暂停时间不会少于rqtp指定的时间,由系统时钟CLOCK_REALTIME测量。

  使用nanosleep()函数对其他行为没有影响,不堵塞任何信号。

 

返回值:

0 :请示的时间间隔结束。

-1:信号中断或失败,并设置errno。

如果rmtp参数不为空,它所引用的timespec结构更新为包含剩余时间的间隔量(请求的时间减去实际睡眠时间)。

如果rmtp参数为NULL,不返回的剩余时间。

 

示例:

req.tv_sec = 0;

req.tv_nsec = 1000;

ret = nanosleep(&req, NULL);

if (-1 == ret)

fprintf (stderr, "\\t nanousleep %8u not support\\n", nDelay);

 

二、精确度对比

如果用于一些 C/S 数据交互等 100ms级以上精度的程序挂起,用sleep, usleep都可以。

如果是在多线程应用场景中,如用于音视频数据的同步,需要100ms以下的精度的程序挂起,则只能用select, 和 nanosleep.

 

这是因为,虽然sleep()和nanosleep()都是使进程睡眠一段时间后被唤醒,但是二者的实现完全不同。

Linux中并没有提供系统调用sleep(),

sleep()是在库函数中实现的,它是通过调用alarm()来设定报警时间,

调用sigsuspend()将进程挂起在信号SIGALARM上。

 

nanosleep()则是Linux中的系统调用,它是使用定时器来实现的,

该调用使调用进程睡眠,并往定时器队列上加入一个timer_list型定时器,time_list结构里包括唤醒时间以及唤醒后执行的函数,

通过nanosleep()加入的定时器的执行函数仅仅完成唤醒当前进程的功能。

系统通过一定的机制定时检查这些队列(比如通过系统调用陷入核心后,从核心返回用户态前,

要检查当前进程的时间片是否已经耗尽,如果是则调用schedule()函数重新调度,该函数中就会检查定时器队列,另外慢中断返回前也会做此检查),

如果定时时间已超过,则执行定时器指定的函数唤醒调用进程。

 

 

三、工程应用

这是FFmpeg的程序挂起,

int av_usleep(unsigned usec)

#if HAVE_NANOSLEEP

struct timespec ts = usec / 1000000, usec % 1000000 * 1000 ;

while (nanosleep(&ts, &ts) < 0 && errno == EINTR);

return 0;

#elif HAVE_USLEEP

return usleep(usec);

#elif HAVE_SLEEP

Sleep(usec / 1000);

return 0;

#else

return AVERROR(ENOSYS);

#endif

 

附:

初六   谦谦君子,用涉大川,吉。

 

以上是关于Linunx的sleep,usleep,select,nonasleep对比与应用的主要内容,如果未能解决你的问题,请参考以下文章

PHP 暂停函数 sleep() 与 usleep() 的区别

Linux的sleep()和usleep()的使用和区别

在 PHP 中 sleep 和 usleep 的行为是不是不同?

sleep()和usleep()

linux 的sleep()、usleep()、nanosleep()函数

C++之sleep/usleep/this_thread::yield/this_thread::sleep_for延时区别(一百四十)