C语言的sleep、usleep、nanosleep等休眠函数的了解与用法
C语言的sleep、usleep、nanosleep等休眠函数的了解与用法
昨天晚上,无聊中捣鼓「死循环」小代码的时候,想用 休眠 函数来慢慢显示输出结果,免得输出结果闪得太快,看都看不清。
但是,使用 sleep 函数的话,最短的休眠时间段是一秒钟,要想看到比较大的输出结果的话,要等好久,于是就查了一下有没有休眠时间段更小的函数。很容易地就找到了两个,一个是 usleep ,一个是 nanosleep 函数。
因为是第一次使用,尤其是 nanosleep 函数的第一个参数是一个没见过的结构体数据类型,所以花了一点点时间去学习和探索背后的细节,当然了,对于俺目前的水平而言,也只是了解了函数本身层面的浅显的细节而已。
捣鼓下来,觉得内容也不少,而且还是挺有用的,就整理了一下,组合成文章,发布在这里,也方便自己以后的回顾学习。
引子
一个无聊的死循环小代码:
#include <stdio.h>int main(int argc, char const *argv[])
{for (char c = 0; c < 128; c++) {printf("cool\n");}return 0;
}
以及 运行过程 展示版:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct timespec n_sleep;n_sleep.tv_sec = 0; //secondes, integer part sleep durationn_sleep.tv_nsec = 5e8L; //nanoseconds, decimal part sleep durationchar c;for (c = 0; c < 128; c++) {printf("char of c :%c\n", c);printf("ASCII num of c :%d\n", c);sleep(1); // 1 susleep(900000); // 0.9 s nanosleep(&n_sleep, NULL); // 0 + 0.5 s}return 0;
}
另外,推荐一下 clang 这款编译器,
它的(1)错误、(2)警告 提示非常直观、准确、体贴。
比如,上面的死循环代码,编译之后,它就贴心地显示了一个警告:
result of comparison of constant 128 with expression of type 'char' is always true[-Wtautological-constant-out-of-range-compare]for (c = 0; c < 128; c++) {~ ^ ~~~
强烈推荐啊!!!
当然,如果还是喜欢或者必须使用 gcc 的话,建议可以将 clang 作为一个辅助选项。
(一) sleep 函数
头文件 unistd.h
头文件 unistd.h 中的原文如下:
/* Make the process sleep for SECONDS seconds, or until a signal arrivesand is not ignored. The function returns the number of seconds lessthan SECONDS which it actually slept (thus zero if it slept the full time).If a signal handler does a `longjmp' or modifies the handling of theSIGALRM signal while inside `sleep' call, the handling of the SIGALRMsignal afterwards is undefined. There is no return value to indicateerror, but if `sleep' returns SECONDS, it probably didn't work.This function is a cancellation point and therefore not marked with__THROW. */
extern unsigned int sleep (unsigned int __seconds);
通过debug的方式,进入 sleep 函数本体内部,可以反向查找到 sleep 函数所在的具体文件是 /glibc-2.23/sysdeps/posix/sleep.c 。
(根据gcc版本的不同,上面的库函数版本号 glibc-2.23 有所不同。)
源文件 sleep.c
sleep 函数的原型代码如下:
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>/* Make the process sleep for SECONDS seconds, or until a signal arrivesand is not ignored. The function returns the number of seconds lessthan SECONDS which it actually slept (zero if it slept the full time).If a signal handler does a `longjmp' or modifies the handling of theSIGALRM signal while inside `sleep' call, the handling of the SIGALRMsignal afterwards is undefined. There is no return value to indicateerror, but if `sleep' returns SECONDS, it probably didn't work. */
unsigned int __sleep(unsigned int seconds)
{int save_errno = errno;const unsigned int max =(unsigned int)(((unsigned long int)(~((time_t)0))) >> 1);struct timespec ts = { 0, 0 };do {if (sizeof(ts.tv_sec) <= sizeof(seconds)) {/* Since SECONDS is unsigned assigning the value to .tv_sec canoverflow it. In this case we have to wait in steps. */ts.tv_sec += MIN(seconds, max);seconds -= (unsigned int)ts.tv_sec;} else {ts.tv_sec = (time_t)seconds;seconds = 0;}if (__nanosleep(&ts, &ts) < 0)/* We were interrupted.Return the number of (whole) seconds we have not yet slept. */return seconds + ts.tv_sec;} while (seconds > 0);__set_errno(save_errno);return 0;
}
weak_alias(__sleep, sleep)
sleep 函数的用法
简单地说, sleep 函数实现的功能是 让程序休眠若干秒钟,时间的最小刻度是「秒」。
extern unsigned int sleep (unsigned int __seconds);
sleep 函数的返回值,
- (1)如果 sleep 函数顺利执行了的话,返回值是实际休眠的时间数,
- (2)如果实际休眠的时间和设定的休眠时间一致的话,返回值是0,
- (3)不会返回表示 错误 信息的值,但是如果返回的值与设定的休眠时间的值一样的话,很可能 sleep 函数其实并没有执行,
- (4)返回值类型是 unsigned int 型,也就是说,是一个 非负数 。
sleep 函数的参数,
- (1)参数的类型是 unsigned int 型,也就是说,是一个 非负数 ,
- (2)参数的时间单位是 秒 。
所以, sleep 函数,使 进程/process 休眠的最短时间段,是一秒钟。
(二) usleep 函数
头文件 unistd.h
头文件 unistd.h 中的原文如下:
/* Sleep USECONDS microseconds, or until a signal arrives that is not blockedor ignored.This function is a cancellation point and therefore not marked with__THROW. */
extern int usleep (__useconds_t __useconds);
查找上面的 sleep.c 文件的时候,在 find 命令的结果中看到了 usleep.c 文件和 sleep.c 文件位于同一个文件夹:
/glibc-2.23/sysdeps/posix/sleep.c 。
(根据gcc版本的不同,上面的库函数版本号 glibc-2.23 有所不同。)
源文件 usleep.c
usleep 函数的原型代码如下:
#include <time.h>
#include <unistd.h>int
usleep (useconds_t useconds)
{struct timespec ts = { .tv_sec = (long int) (useconds / 1000000),.tv_nsec = (long int) (useconds % 1000000) * 1000ul };/* Note the usleep() is a cancellation point. But since we callnanosleep() which itself is a cancellation point we do not haveto do anything here. */return __nanosleep (&ts, NULL);
}
名称 usleep 的第一个字母 u 代表的是时间单位 微秒 的第一个字母。
虽然实际上是希腊字母的 μ ,但英语键盘里不方便敲出这个字母,所以就用了样子相似的英文字母 u 。
时间单位 微秒 的英文单词是 microsecond ,是由词根 micro 和 second 组合而成的单词。
微秒 是 10的负6次方 秒。
另外,还有一个以字母 m 开头的时间单位的英文单词 millisecond ,意思是 毫秒 ,也就是 千分之一秒。
注意,区分 micro 和 milli ,一个是 微 ,一个是 毫 。
usleep 函数的用法
简单地说, usleep 函数实现的功能是 让程序休眠若干「微秒」,时间的最小刻度是「微秒」,10的负6次方 秒。
/* Sleep USECONDS microseconds, or until a signal arrives that is not blockedor ignored.This function is a cancellation point and therefore not marked with__THROW. */
extern int usleep (__useconds_t __useconds);
usleep 函数的返回值
网上查到的是:成功返回0,出错返回-1。
usleep 函数的参数
- (1) 参数的类型是 __useconds_t ,这个类型的定义要查找好几个文件才找得到,
- (2) 首先是找到了头文件 types.h ,具体路径是 /glibc/include/sys/types.h ,可惜这里面没有明确、具体的定义,
- (3) 然后还得找到头文件 typesizes.h ,具体路径是 ==/glibc/sysdeps/mach/hurd/bits/typesizes.h ==,这里终于有了,
- (4) 第一个宏, #define __USECONDS_T_TYPE __U32_TYPE ,在 typesizes.h 文件里,
- (5) 第二个宏, #define __U32_TYPE unsigned int ,在 types.h 文件里,
- (6) 真是折腾啊!这下总算知道 __useconds_t 就是 unsigned int 类型了,也就是 非负整数。
- (7) 参数的时间单位是 微秒 。
所以, usleep 函数,使 进程/process 休眠的最短时间段,是一微秒。
(三) nanosleep 函数
头文件 time.h
这个 time.h 头文件的路径是 /glibc/time/time.h 。
在C语言自带的库目录里面,有好几个不同目录下的 time.h 文件,只有这个才是定义了 nanosleep 函数的。
也不知道,编译器在预处理阶段去获取的 time.h 到底是哪个? 或者说,全部都获取过来了?
头文件 time.h 中的原文如下:
/* Pause execution for a number of nanoseconds.This function is a cancellation point and therefore not marked with__THROW. */
extern int nanosleep (const struct timespec *__requested_time,struct timespec *__remaining);
函数名称的 nano 是 纳米、纳秒 等计量单位的开头字母,一纳秒是10的负9次方 秒,是10的负6次方 毫秒,是10的负3次方 微秒。
源文件 nanosleep.c
下面是这个路径 /glibc/posix/nanosleep.c 的文件内容。
在C语言自带的函数库中搜索 nanosleep ,出来的结果同样有好几个,暂时分不清到底是哪个,先采用了这个。
nanosleep 函数的原型代码如下:
#include <errno.h>
#include <time.h>/* Pause execution for a number of nanoseconds. */
int
__nanosleep (const struct timespec *requested_time,struct timespec *remaining)
{__set_errno (ENOSYS);return -1;
}
stub_warning (nanosleep)hidden_def (__nanosleep)
weak_alias (__nanosleep, nanosleep)
nanosleep 函数的用法
简单地说, nanosleep 函数实现的功能是 让程序休眠若干「纳秒」,时间的最小刻度是「纳秒」,10的负9次方 秒。
/* Pause execution for a number of nanoseconds.This function is a cancellation point and therefore not marked with__THROW. */
extern int nanosleep (const struct timespec *__requested_time,struct timespec *__remaining);
nanosleep 函数的返回值
网上查到的是:成功返回0,出错返回-1。
这个函数功能是暂停某个进程直到你规定的时间后恢复,参数 req 就是你要暂停的时间,其中 req->tv_sec 是以秒为单位,而 tv_nsec 以纳秒为单位(10的-9次方秒)。
由于调用 nanosleep 是进程进入 TASK_INTERRUPTIBLE ,这种状态是会相应信号而进入 TASK_RUNNING 状态的,这就意味着有可能会没有等到你规定的时间就因为其它信号而唤醒,此时函数返回 -1 ,切换剩余的时间会被记录在 rem 中。
return值: 若进程暂停到参数 *req 所指定的时间,成功则返回0;若有信号中断则返回-1,并且将剩余微秒数记录在 *rem 中。
nanosleep 函数的参数
第一个参数 *__requested_time 的数据类型是 struct timespec ,定义在 time.h 文件中,
具体是定义在 /glibc/time/bits/types/struct_timespec.h 文件中的。
文件内容如下:
#include <bits/types.h>/* POSIX.1b structure for a time value. This is like a `struct timeval' buthas nanoseconds instead of microseconds. */
struct timespec
{__time_t tv_sec; /* Seconds. */__syscall_slong_t tv_nsec; /* Nanoseconds. */
};
对于 struct timespec 数据类型的详细说明如下:
(昨天晚上上网查资料、自行测试的时候,自己写的英文笔记,请忽略语法疏漏~)
- in header file of C lib, time.h, declaration as below:
struct timespec; (since C11)
struct timespec {time_t tv_sec; // secondslong tv_nsec; // nanoseconds
};
Member objects / 结构体成员:
time_t tv_sec whole seconds (valid values are >= 0)
long tv_nsec nanoseconds (valid values are [0, 999999999])time_t 类型是 long 型,成员 tv_sec 决定 休眠持续时间段的 整数部分:
member of 「tv_sec」 at the type of 「time_t」,
aka (also know as) 「long」 type,
determines the integer part of sleep duration;time_t 类型是 long 型,成员 tv_nsec 决定 休眠持续时间段的 小数部分:
member of 「tv_nsec」 at the type of 「long」,
and in the range of [0, 999999999] or [0,1e9),
that means tv_nsec is forever less than 1 second,
determines the decimal part of sleep duration.就算赋值给成员 tv_nsec 的数值直接计算下来超过了一秒,成员 tv_nsec 获得的实际的值也是被取余后的结果。
even if a value more than 999999999 ns given to tv_nsec,
actually what tv_nsec will get is a value cut down extra part,
eg. 1e9L or 100000000 will be cut the high bits and leave 0 to tv_nsec.总而言之,整个的休眠时间段是 整数部分的 tv_sec 加上 小数部分的 tv_nsec 组成的。
so, the whole sleep duration is tv_sec + tv_nsec,
just as 「integer part + decimal part」 of the whole sleep duration.
所以, nanosleep 函数,使 进程/process 休眠的最短时间段,是一纳秒。
注意
- unistd.h 是 unix 系统标准头文件,用于系统调用,相当于 win32 中的 windows.h , unistd.h 定义的函数只能用于 UNIX 环境中,而不能用于 windows 。
- 所以 sleep 和 usleep 只能用于 Linux / Unix 下,而不能用于 windows 。
- nalosleep 和 其它时间日期操作函数 一样,都是定义在 time.h 中的,所以都适用。
- 使用 clang 编译c程序文件的时候,提示「警告」说, usleep 和 nanosleep 在 C99 中是非法的。不过因为实际采用的是 C11 标准,所以还是编译通过了,也能正常执行。这里只是 clang 的一个善意的提醒吧。
结尾
C语言的sleep、usleep、nanosleep等休眠函数的了解与用法相关推荐
- 编写C语言跨平台函数(以清屏和休眠函数为例)
支持C语言的平台有许多,常见的编译器如VC.gcc.Clang等.不同的编译器共同点是都支持标准C(ANSI C),但是各自却又有自己独立的.平台相关的功能以及函数接口.这通常为程序的移植性带来很多问 ...
- c语言休眠函数 vs,编纂C语言跨平台函数(以清屏和休眠函数为例)
编写C语言跨平台函数(以清屏和休眠函数为例) 支持C语言的平台有许多,常见的编译器如VC.gcc.Clang等.不同的编译器共同点是都支持标准C(ANSI C),但是各自却又有自己独立的.平台相关的功 ...
- Linux下的微秒级定时器: usleep, nanosleep, select, pselect
Linux下的微秒级定时器: usleep, nanosleep, select, pselect 标签: linuxnulldelaystructdate 2012-02-07 23:29 4979 ...
- linux下usleep nanosleep select的比较经历
sleep:单位为秒,1秒 usleep:单位为微秒,1/1000 秒 select:单位为微秒,1/1000 000 秒 nanosleep:单位为毫微秒,也就是纳秒,1/1000 000 000 ...
- C语言休眠函数和暂停函数使用案例
本程序使用C语言休眠函数和暂停函数于光棍节无聊时所做,仅供娱乐! 祝大家光棍节快乐! 源码开放,只需要修改里面文字然后用vc++6.0编译即可. Debug目录下生成的*.exe程序复制出来发给对方即 ...
- C++:详解C++11 线程休眠函数
休眠函数 简介 1: 让线程休眠一段时间 1.1:std::chrono 的时钟 clock 简介 C++11 之前并未提供专门的休眠函数,C语言的 sleep.usleep函数其实是系统提供的函数, ...
- linux c++ 等待函数,JavaScript在nodejs中实现sleep休眠函数wait等待的方法
参考文档: JavaScript在nodejs中实现sleep休眠函数wait等待的方法: https://www.bas369.com/more/l... js的休眠实现---sleep(): ht ...
- R语言使用party包中的ctree函数构建条件推理决策树的流程和步骤、条件推理决策树是传统决策树的一个重要变体、条件推理树的分裂是基于显著性测试而不是熵/纯度/同质性度量来选择分裂
R语言使用party包中的ctree函数构建条件推理决策树的流程和步骤(Conditional inference trees).条件推理决策树是传统决策树的一个重要变体.条件推理树的分裂是基于显著性 ...
- R语言ggplot2可视化:通过在element_text函数中设置ifelse判断条件自定义标签文本的显示格式:例如、粗体、斜体等
R语言ggplot2可视化:通过在element_text函数中设置ifelse判断条件自定义标签文本的显示格式:例如.粗体.斜体等 目录
最新文章
- sqlserver2000换成mysql_将Microsoft SQL Server 2000数据库转换成MySQL数据库
- 访谈实录:网管员如何踏上高薪之路(1)
- 网络流24题之魔术球问题
- register_chrdev深入分析
- oracle的获取年月日时间,获取5年前日期
- cisco switch configuration
- Continue to debug QDD504 read - Service Order extractor debug
- 怎没用计算机算e的,小E教你们如何用计算机算虚数
- Atitit IT办公场所以及度假村以及网点以及租房点建设之道 attilax总结
- javaScript位移密码算法挑战
- 重庆邮电大学c语言题库
- 使用jQuery实现轮播图
- FISCO-BCOS平台,搭建第一个区块链应用
- 汉语教学备课工具推荐
- html css语义化
- ENDNOTE中使用Adobe打开PDF后提示“只读无法保存”
- obsidian apk下载办法
- Android 下载和更新APK
- 稳定域的画法 matlab,第05讲 MATLABsimulink稳定性分析、时域分析.ppt
- ubuntu按装佳能c3520打印机驱动
热门文章
- nodejs+vue+java绿色环保网站springboot460
- CSS3鼠标悬停图片遮罩动画js特效
- 微信公众号发送模版消息
- 【超图+CESIUM】【基础API使用示例】16、超图|CESIUM -设置地球模式:椭球模式、圆球模式
- 高端操作!实现RecyclerView的上下拖拽
- python3入门之 deque(双向队列)
- Hardware assisted virtualization and data execution protection must be enabled in the BIOS.
- c语言安卓app开发,手机CAPP - C语言安卓开发
- 计算机辅助设计capp设计,[高等教育]09第四章 计算机辅助设计与制造技术CAPP.ppt...
- 一些微信第三方登录需要注意的地方