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

本文深入探讨了程序挂起的相关技术,包括秒、毫秒、微秒、纳秒和皮秒的换算,以及sleep、usleep、select、pselect、nanosleep函数的用法、精度对比与工程应用。特别强调了在不同场景下选择合适函数的重要性,如多线程同步、C/S数据交互等。同时提供了FFmpeg中程序挂起的实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

时钟换算:

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

}

 

附:

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

 

<think>好的,我现在要回答用户关于Linux线程中sleepusleep函数的功能区别的问题。首先,我需要回忆这两个函数的基本用法和它们所在的头文件。记得sleep函数是以秒为单位的,而usleep则是以微秒为单位,但可能已经被弃用了?或者是不是被nanosleep取代了? 然后,我得确认它们的函数原型。比如,sleep的返回值是剩余的秒数,如果在休眠期间被信号中断的话。而usleep可能返回0或者-1,并且设置errno。不过,用户提到的是在线程中的使用,所以需要考虑多线程环境下的表现。比如,这些函数是否会让整个进程休眠,还是只影响当前线程?根据POSIX标准,sleep应该是让当前线程挂起,而不会影响进程中的其他线程,这很重要。 接下来是区别部分。除了时间单位的差异,可能还有精度问题。usleep提供微秒级休眠,但实际上受系统调度和时钟精度的影响,可能无法精确到微秒。另外,usleep已经被标记为废弃,推荐使用nanosleep,这一点需要提到。而sleep函数虽然还在使用,但可能在高精度需求下不够用。 使用场景的话,sleep适合需要较长时间延迟的情况,比如几秒。而usleep适合需要更短暂休眠的场景,比如几百毫秒或微秒级别的等待,但需要注意可移植性问题,因为usleep可能不被所有系统支持,或者建议改用nanosleep。同时,在线程中使用时,这两个函数是否安全?比如,是否会导致线程挂起时仍持有锁,进而引发死锁?可能需要提醒用户注意同步机制,比如结合条件变量使用,而不是单纯依赖休眠。 还需要考虑信号处理的问题,如果线程在sleep期间收到信号,会不会提前唤醒,这会影响程序的行为,特别是多线程环境下信号的处理方式。比如,每个线程可以有自己的信号掩码,但信号处理是进程范围的,这可能导致某些意外中断。 另外,用户提供的引用中提到了条件变量和读写锁,可能在线程同步中更推荐使用这些机制而不是单纯的休眠,因为休眠可能导致忙等待或者无法及时响应状态变化。比如,在等待某个资源时,使用条件变量可以让线程挂起直到被唤醒,而不是不断轮询,这样更高效。 总结一下,回答的结构应该先介绍两个函数的功能,然后详细对比它们的区别,包括单位、精度、可移植性、返回值等,再讨论使用场景,并提到替代函数如nanosleep,最后结合线程安全和同步机制给出建议,比如避免长时间休眠而使用条件变量等。同时,引用提供的资料,比如提到条件变量和线程池的实现,可能相关的应用场景。</think>### Linux线程中`sleep``usleep`的功能区别 #### 1. **功能说明** - **`sleep`函数** 用于使当前线程挂起指定的秒数。若休眠期间收到信号被中断,会返回剩余的未休眠时间(以秒为单位)。 函数原型: ```c unsigned int sleep(unsigned int seconds); ``` 示例:`sleep(2);` 表示线程暂停2秒。 - **`usleep`函数** 用于使当前线程挂起指定的微秒(1秒=1,000,000微秒)。但需注意,`usleep`已被POSIX标记为**废弃**,建议改用`nanosleep`[^1]。 函数原型: ```c int usleep(useconds_t usec); ``` 示例:`usleep(500000);` 表示线程暂停0.5秒。 --- #### 2. **主要区别** | **特性** | **`sleep`** | **`usleep`** | |----------------|---------------------------|--------------------------------| | **时间单位** | 秒(seconds) | 微秒(microseconds) | | **精度** | 低(秒级) | 高(微秒级,但受系统调度限制) | | **可移植性** | POSIX标准,广泛支持 | 已废弃,部分系统可能不支持 | | **返回值** | 剩余未休眠秒数 | 成功返回0,失败返回-1并设errno | | **替代函数** | 无 | `nanosleep` | --- #### 3. **使用场景** - **`sleep`适用场景** - 需要较长时间的延迟(如秒级等待)。 - 简单的超时控制或调试场景。 示例: ```c while (task_not_ready) { sleep(1); // 每秒检查任务状态 } ``` - **`usleep`适用场景** - 需要短暂休眠(如毫秒或微秒级操作)。 - 高精度计时需求(但需注意实际精度受系统限制)。 示例: ```c usleep(1000); // 等待1毫秒 ``` --- #### 4. **线程安全注意事项** - **线程级挂起** 两者均仅挂起**当前线程**,不会阻塞整个进程[^2]。 - **信号中断** 若休眠期间收到信号,`sleep`会提前返回剩余时间,而`usleep`可能返回-1(需检查`errno`)。 - **替代方案建议** - 使用`nanosleep`替代`usleep`,支持纳秒级精度且符合POSIX标准。 - 在需要同步的场景(如等待资源),优先使用**条件变量**(`pthread_cond_t`)而非忙等待[^3]。 --- #### 5. **代码示例对比** ```c // 使用sleep实现秒级等待 void thread_func1() { sleep(3); // 休眠3秒 // 执行后续操作 } // 使用usleep实现微秒级等待(不推荐) void thread_func2() { usleep(300000); // 休眠0.3秒 // 执行后续操作 } // 更推荐的nanosleep实现 void thread_func3() { struct timespec req = {0, 300000000}; // 0.3秒 nanosleep(&req, NULL); } ``` ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北雨南萍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值