Linux定时器是一种软件机制,用于在指定的时间间隔或特定时间点执行特定的任务。它是基于内核的机制,可以用于各种应用场景,如定时任务调度、延时处理、周期性事件触发等。
运作机制(工作原理):Linux定时器的工作原理主要分为两个部分:定时器的创建和定时器的触发。
定时器的创建:创建定时器的步骤包括:
通过这些步骤,将定时器添加到内核的定时器列表中。
定时器的触发:当定时器超时时间到达时,内核会触发定时器,执行注册的回调函数。回调函数可以是用户指定的函数,用于执行特定的任务。
数据结构:Linux定时器的数据结构主要有以下几种:
定时器结构体(struct timer_list):用于定义定时器的属性,如超时时间、回调函数等。
内核定时器列表:内核维护了一个定时器列表,用于存储所有的定时器。通过链表等数据结构将定时器连接起来,方便管理和触发。
优点:
缺点:
应用场景:Linux定时器广泛应用于以下场景:
POSIX定时器:POSIX定时器是一种与Linux定时器类似的机制,提供了更高级的接口和功能,可以实现更复杂的定时任务调度。
内核定时器API:Linux内核提供了一系列的定时器API,如timer_create、timer_settime、timer_gettime等,用于创建和操作定时器。
定时器分辨率:定时器分辨率是指定时器的最小时间单位,决定了定时器的精度。在Linux中,定时器分辨率一般为10ms。
网络应用:定时器可以用于实现网络超时重传、心跳检测等功能。
嵌入式系统:定时器可以用于实现周期性任务,如定时采集传感器数据、定时更新显示等。
多媒体应用:定时器可以用于实现音视频播放、动画效果等的定时控制。
用户空间的定时器和 Linux 内核中的定时器是两个不同的概念,它们的区别如下:
位置不同:
权限不同:
实现方式不同:
setitimer()
、timer_settime()
)或库函数(如 sleep()
、usleep()
)来实现的。精度不同:
用途不同:
选择使用哪个定时器函数取决于具体的需求和使用场景。以下是一些考虑因素:
功能需求:根据需要选择适合的功能。
setitimer()
函数。timer_settime()
函数。init_timer()
函数。精度要求:不同的定时器函数可能具有不同的精度。如果需要较高的精度,可以考虑使用 Linux 内核中的定时器函数。
编程环境:根据所使用的编程环境和语言,选择相应的定时器函数。
setitimer()
和 timer_settime()
是用户空间的函数,适用于大多数编程语言。init_timer()
是在内核中使用的函数,需要在内核模块或驱动程序中使用。可移植性:一些定时器函数可能在不同的操作系统或平台上具有不同的行为或支持程度。如果需要编写可移植的代码,需要考虑函数的可移植性。
总的来说,这两者都是 Linux 系统中的函数,选择使用哪个定时器函数应该根据具体需求和使用场景进行评估。
对于大多数应用程序来说,timer_settime()
函数是一个较新且功能强大的选择,可以在定时器到期时执行回调函数。但在某些特定的场景下,可能需要使用其他定时器函数来满足需求。
总结:
setitimer()
、timer_settime()
、sleep()
、usleep()
)是通过系统调用或库函数提供的,用于在用户空间中设置和管理定时器。init_timer()
、定时器中断处理函数)是在内核中实现的,用于在内核中设置和管理定时器。函数名 | 功能 | 参数 | 返回值 |
---|---|---|---|
timer_create() |
创建一个新的定时器 | clockid_t clockid :时钟标识符struct sigevent *sevp :定时器超时时的通知方式timer_t *timerid :返回的定时器标识符 |
int :成功返回0,失败返回错误码 |
timer_settime() |
设置定时器的超时时间和回调函数 | timer_t timerid :定时器标识符int flags :定时器行为标志const struct itimerspec *new_value :新的超时时间和回调函数struct itimerspec *old_value :旧的超时时间和回调函数 |
int :成功返回0,失败返回错误码 |
timer_gettime() |
获取定时器的当前超时时间和剩余时间 | timer_t timerid :定时器标识符struct itimerspec *curr_value :当前超时时间和剩余时间 |
int :成功返回0,失败返回错误码 |
timer_delete() |
删除一个已创建的定时器 | timer_t timerid :定时器标识符 |
int :成功返回0,失败返回错误码 |
timer_getoverrun() |
获取定时器超时次数 | timer_t timerid :定时器标识符 |
int :成功返回超时次数,失败返回错误码 |
timer_settime64() |
设置定时器的超时时间和回调函数(支持 64 位的超时时间) | timer_t timerid :定时器标识符int flags :定时器行为标志const struct __kernel_itimerspec64 *new_value :新的超时时间和回调函数struct __kernel_itimerspec64 *old_value :旧的超时时间和回调函数 |
int :成功返回0,失败返回错误码 |
timer_gettime64() |
获取定时器的当前超时时间和剩余时间(支持 64 位的超时时间) | timer_t timerid :定时器标识符struct __kernel_itimerspec64 *curr_value :当前超时时间和剩余时间 |
int :成功返回0,失败返回错误码 |
timerfd_create() |
创建一个新的定时器文件描述符 | int clockid :时钟标识符int flags :定时器行为标志 |
int :成功返回定时器文件描述符,失败返回错误码 |
timerfd_settime() |
设置定时器文件描述符的超时时间和回调函数 | int fd :定时器文件描述符int flags :定时器行为标志const struct itimerspec *new_value :新的超时时间和回调函数struct itimerspec *old_value :旧的超时时间和回调函数 |
int :成功返回0,失败返回错误码 |
timerfd_gettime() |
获取定时器文件描述符的当前超时时间和剩余时间 | int fd :定时器文件描述符struct itimerspec *curr_value :当前超时时间和剩余时间 |
int :成功返回0,失败返回错误码 |
clock_gettime() |
获取指定时钟的当前时间 | clockid_t clock_id :时钟标识符struct timespec *tp :当前时间 |
int :成功返回0,失败返回错误码 |
clock_settime() |
设置指定时钟的时间 | clockid_t clock_id :时钟标识符const struct timespec *tp :新的时间 |
int :成功返回0,失败返回错误码 |
clock_getres() |
获取指定时钟的分辨率 | clockid_t clock_id :时钟标识符struct timespec *res :分辨率 |
int :成功返回0,失败返回错误码 |
nanosleep() |
使当前进程休眠指定的时间 | const struct timespec *req :休眠时间struct timespec *rem :剩余的休眠时间 |
int :成功返回0,失败返回剩余的休眠时间 |
usleep() |
使当前进程休眠指定的微秒数 | unsigned int usec :休眠的微秒数 |
int :成功返回0,失败返回错误码 |
------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
alarm() |
设置一个定时器,在指定的时间间隔后发送 SIGALRM 信号给当前进程 |
unsigned int seconds :定时器的时间间隔 |
unsigned int :成功返回剩余的定时器时间,失败返回错误码 |
setitimer() |
设置定时器的超时时间和回调函数 | int which :定时器类型const struct itimerval *new_value :新的超时时间和回调函数struct itimerval *old_value :旧的超时时间和回调函数 |
int :成功返回0,失败返回错误码 |
getitimer() |
获取定时器的当前超时时间和剩余时间 | int which :定时器类型struct itimerval *curr_value :当前超时时间和剩余时间 |
int :成功返回0,失败返回错误码 |
signal() |
设置一个函数来处理信号,即带有 sig 参数的信号处理程序 | int signum :信号编号void (*handler)(int) :信号处理函数 |
void (*handler)(int) :之前设置的信号处理函数 |
以上是一些常用的 Linux 定时器相关的 C 函数,这些函数可以用于设置和管理定时器,获取定时器的超时时间和剩余时间,创建定时器文件描述符等。具体的使用方法和参数细节可以参考相关函数的文档和示例代码。
表格中还包括了 alarm()
、setitimer()
和 getitimer()
、signal()
这几个函数。
这几个函数也可以用于设置和管理定时器,获取定时器的超时时间和剩余时间,但是它们的使用方式和参数与表格中的其它函数有所不同。具体的使用方法和参数细节可以参考相关函数的文档和示例代码。
函数名 | 功能 | 参数 |
---|---|---|
hrtimer_init() |
初始化一个高精度定时器 | struct hrtimer *timer - 定时器对象clockid_t clock_id - 时钟 IDenum hrtimer_mode mode - 定时器模式 |
hrtimer_start() |
启动一个高精度定时器 | struct hrtimer *timer - 定时器对象ktime_t time - 定时器到期的时间const enum hrtimer_mode mode - 定时器模式 |
hrtimer_cancel() |
取消一个高精度定时器 | struct hrtimer *timer - 定时器对象 |
hrtimer_forward() |
将一个高精度定时器向前调整指定的时间 | struct hrtimer *timer - 定时器对象ktime_t now - 当前时间ktime_t interval - 调整的时间间隔 |
hrtimer_get_remaining() |
获取一个高精度定时器的剩余时间 | struct hrtimer *timer - 定时器对象ktime_t *remaining - 剩余时间 |
hrtimer_set_expires() |
设置一个高精度定时器的到期时间 | struct hrtimer *timer - 定时器对象ktime_t time - 到期时间 |
hrtimer_active() |
检查一个高精度定时器是否处于活动状态 | struct hrtimer *timer - 定时器对象 |
hrtimer_init_sleeper() |
初始化一个高精度定时器睡眠器 | struct hrtimer_sleeper *sl - 睡眠器对象 |
hrtimer_start_range_ns() |
启动一个高精度定时器,并指定到期时间的范围 | struct hrtimer *timer - 定时器对象ktime_t time - 定时器到期的时间u64 delta_ns - 到期时间的范围 |
hrtimer_cancel() |
取消一个高精度定时器 | struct hrtimer *timer - 定时器对象 |
hrtimer_forward() |
将一个高精度定时器向前调整指定的时间 | struct hrtimer *timer - 定时器对象ktime_t now - 当前时间ktime_t interval - 调整的时间间隔 |
hrtimer_get_remaining() |
获取一个高精度定时器的剩余时间 | struct hrtimer *timer - 定时器对象ktime_t *remaining - 剩余时间 |
hrtimer_set_expires_range_ns() |
设置一个高精度定时器的到期时间的范围 | struct hrtimer *timer - 定时器对象ktime_t time - 到期时间u64 delta_ns - 到期时间的范围 |
hrtimer_active() |
检查一个高精度定时器是否处于活动状态 | struct hrtimer *timer - 定时器对象 |
alarm()
设置定时器并处理信号#include
#include
#include
#include
// 信号处理函数
void signal_handler(int signum)
{
printf("Received SIGALRM signal\n");
// 处理定时器到期的操作
}
int main()
{
// 注册信号处理函数
signal(SIGALRM, signal_handler);
// 设置定时器,5秒后发送SIGALRM信号
alarm(5);
// 等待信号到达
pause();
return 0;
}
setitimer()
设置定时器并处理定时器到期事件#include
#include
#include
#include
// 定时器到期时的回调函数
void timer_callback(int signum)
{
printf("Timer expired!\n");
// 处理定时器到期的操作
}
int main()
{
struct itimerval timer;
// 注册定时器到期的信号处理函数
signal(SIGALRM, timer_callback);
// 设置定时器的初始值为2秒,间隔为1秒
timer.it_value.tv_sec = 2;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
// 设置定时器
if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
perror("setitimer");
exit(EXIT_FAILURE);
}
// 等待定时器到期
sleep(5);
return 0;
}
getitimer()
获取定时器的当前值#include
#include
#include
int main()
{
struct itimerval timer;
// 获取定时器的当前值
if (getitimer(ITIMER_REAL, &timer) == -1) {
perror("getitimer");
exit(EXIT_FAILURE);
}
// 输出定时器的当前值
printf("Timer value: %ld seconds %ld microseconds\n", timer.it_value.tv_sec, timer.it_value.tv_usec);
printf("Timer interval: %ld seconds %ld microseconds\n", timer.it_interval.tv_sec, timer.it_interval.tv_usec);
return 0;
}
以上示例代码展示了如何使用 alarm()
、setitimer()
和 getitimer()
函数来创建、设置和使用定时器。
第一个示例使用 alarm()
设置定时器,当定时器到期时,会发送 SIGALRM 信号,并通过注册的信号处理函数进行处理。
第二个示例使用 setitimer()
设置定时器,定时器每隔1秒触发一次,并在到期时调用回调函数进行处理。
第三个示例使用 getitimer()
获取定时器的当前值,并输出定时器的当前值和间隔值。
#include
#include
static struct hrtimer hr_timer;
enum hrtimer_restart timer_callback(struct hrtimer *timer)
{
// 定时器到期时的处理逻辑
printk(KERN_INFO "Timer expired!\n");
// 重新设置定时器的到期时间
hrtimer_forward_now(timer, ms_to_ktime(1000));
return HRTIMER_RESTART;
}
int init_module(void)
{
// 初始化定时器
hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
// 设置定时器的到期时间和回调函数
hr_timer.function = timer_callback;
hrtimer_start(&hr_timer, ms_to_ktime(1000), HRTIMER_MODE_REL);
return 0;
}
void cleanup_module(void)
{
// 取消定时器
hrtimer_cancel(&hr_timer);
}
以上示例代码使用了内核中的 hrtimer_init()
和 hrtimer_start()
函数创建和启动了一个高精度定时器。
在定时器到期时,会触发回调函数 timer_callback
,并在其中处理定时器到期的逻辑。
在示例代码中,定时器每隔一秒触发一次,并输出 “Timer expired!”。最后,使用 hrtimer_cancel()
函数取消了定时器。
setitimer
函数是一个系统调用,用于设置定时器。它可以用于在指定的时间间隔内触发信号,并执行相应的信号处理函数。
函数原型如下:
#include
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
参数说明:
which
:指定定时器类型,可以是以下值之一:
ITIMER_REAL
:真实时间定时器,使用系统的真实时间计时。ITIMER_VIRTUAL
:虚拟时间定时器,仅在进程执行用户态代码时计时。ITIMER_PROF
:虚拟时间和系统时间定时器,包括进程执行用户态代码和内核态代码的时间。new_value
:指向 struct itimerval
结构体的指针,用于设置新的定时器值。
it_interval
:定时器的间隔时间,即定时器触发信号的时间间隔。it_value
:定时器的初始值,即第一次触发信号的时间。old_value
:指向 struct itimerval
结构体的指针,用于保存旧的定时器值。返回值:
示例用法:
#include
#include
#include
void timer_handler(int signum)
{
printf("Timer expired!\n");
}
int main()
{
struct itimerval timer;
struct sigaction sa;
// 安装信号处理函数
sa.sa_handler = timer_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
// 设置定时器
timer.it_value.tv_sec = 1; // 初始值为 1 秒
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1; // 间隔为 1 秒
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
// 等待定时器触发
while (1)
{
}
return 0;
}
以上示例代码演示了如何使用 setitimer
函数设置一个定时器,每隔一秒触发一次 SIGALRM
信号,并执行相应的信号处理函数 timer_handler
。
—————————————————————————————------———————————————————————
函数名 | signal() |
---|---|
功能 | 设置信号处理函数 |
参数 | int signum :信号编号void (*handler)(int) :信号处理函数 |
返回值 | void (*handler)(int) :之前设置的信号处理函数 |
功能介绍:
signal()
函数用于设置信号处理函数,用于处理特定信号的到达。当特定信号到达时,系统会调用设置的信号处理函数。该函数可以用于捕获和处理各种信号,例如中断信号、终止信号等。
参数介绍:
int signum
:信号编号,表示要设置的信号。void (*handler)(int)
:信号处理函数,是一个指向函数的指针,用于处理特定信号的到达。函数的参数是信号编号。返回值介绍:
void (*handler)(int)
:之前设置的信号处理函数。如果之前未设置信号处理函数,则返回 SIG_DFL
(默认信号处理函数)。
以下是将 Linux 定时器的 signal()
函数的示例:
#include
#include
#include
#include
#include
void timer_handler(int signum) {
printf("Timer expired.\n");
}
int main() {
struct sigaction sa;
struct itimerval timer;
// 安装信号处理程序
sa.sa_handler = timer_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
// 设置定时器
timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
// 无限循环,等待定时器信号
while (1) {
sleep(1);
}
return 0;
}
在上面的代码中,
timer_handler()
函数,用于处理定时器信号。main()
函数中,我们使用 sigaction()
函数安装信号处理程序,将 timer_handler()
函数与 SIGALRM
信号关联起来。setitimer()
函数设置定时器,使其每隔 1 秒触发一次。最后,我们使用一个无限循环来等待定时器信号。请注意,上述代码仅为示例,实际使用时可能需要根据具体需求进行适当的修改。
另外,为了保证定时器的准确性,建议在使用 setitimer()
函数之前将 struct itimerval
结构体中的值初始化为 0。
那么signal()
注册的信号捕捉函数 与 setitimer()
设置的定时器 是如何绑定的?
signal()
函数和 setitimer()
函数之间没有直接的绑定关系。它们分别用于不同的目的,但可以一起使用来实现定时器功能。signal()
函数用于设置信号处理函数,当指定的信号到达时,系统会调用设置的信号处理函数。通过设置合适的信号处理函数,我们可以捕获和处理特定的信号,例如定时器信号。setitimer()
函数用于设置定时器,它可以在指定的时间间隔内周期性地触发一个信号。通过设置定时器,我们可以在定时器信号到达时执行相应的操作。signal()
函数设置一个信号处理函数,然后使用 setitimer()
函数设置一个定时器,使其以一定的时间间隔触发一个信号。当定时器信号到达时,系统会调用设置的信号处理函数。————————————————————————————————————————————————————
setitimer()
、timer_settime()
和 init_timer()
是三个不同的函数,用于设置定时器。
setitimer()
函数是一个系统调用,用于设置定时器。它可以用于在指定的时间间隔内触发信号,并执行相应的信号处理函数。setitimer()
函数的原型如下:
#include
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
setitimer()
函数的参数 new_value
用于设置新的定时器值,包括定时器的初始值和间隔时间。timer_settime()
是一个用户空间的函数,用于设置和修改 POSIX 定时器的参数。
函数原型如下:
int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
timer_settime()
函数用于设置定时器的参数,其中包括定时器的间隔时间和初始值。flags
参数设置为 TIMER_ABSTIME
,则 new_value
参数中的时间值被视为绝对时间;init_timer()
函数是内核中的一个函数,用于初始化一个定时器结构体。它的原型如下:
void init_timer(struct timer_list *timer);
init_timer()
函数的参数 timer
是一个指向 timer_list
结构体的指针,用于初始化定时器结构体。timer_list
是用于在内核中管理定时器的数据结构,包含定时器的超时时间、回调函数等信息。它们之间的主要区别如下:
功能不同:
setitimer()
是一个旧的函数,用于设置定时器的初始值和间隔值,并在定时器到期时发送指定的信号。timer_settime()
是一个新的函数,用于设置定时器的初始值和间隔值,并在定时器到期时执行指定的回调函数。init_timer()
是一个 Linux 内核中的函数,用于初始化一个内核定时器,与用户空间的定时器设置无关。精度不同:
setitimer()
使用 struct itimerval
结构来设置定时器的值,其中的时间单位是微秒级别(us)。timer_settime()
使用 struct itimerspec
结构来设置定时器的值,其中的时间单位可以是纳秒级别(ns)。init_timer()
是在内核中初始化一个定时器,精度取决于系统的时钟频率。信号处理不同:
setitimer()
在定时器到期时发送指定的信号(如 SIGALRM),需要通过注册信号处理函数来处理定时器到期事件。timer_settime()
在定时器到期时执行指定的回调函数,无需注册信号处理函数。init_timer()
是在内核中初始化一个定时器,不涉及用户空间的信号处理。使用环境不同:
setitimer()
和 timer_settime()
是用户空间的函数,用于在应用程序中设置定时器。init_timer()
是 Linux 内核中的函数,用于在内核中初始化定时器。总结:
setitimer()
是一个较旧的系统调用函数,用于在用户空间设置定时器并触发相应的信号。它是一个比较底层的接口,可以精确控制定时器的时间间隔和触发方式。使用 setitimer()
可以实现定时任务、周期性任务等功能。timer_settime()
是一个较新的系统调用函数,用于在用户空间设置定时器并执行回调函数;init_timer()
是内核中的函数,主要用于内核开发中。它用于初始化定时器结构体,并将定时器添加到内核的定时器列表中。在内核开发中,可以使用 init_timer()
创建和管理定时器,然后使用其他函数(如 mod_timer()
)设置定时器的超时时间和回调函数。setitimer()
和 timer_settime()
都可以用于在用户空间中设置定时器,但它们的使用方式略有不同。
setitimer()
使用 struct itimerval
结构体来设置定时器的初始值和间隔值。它可以设置定时器的绝对时间和相对时间,通过发送指定的信号来触发定时器到期事件。需要注册信号处理函数来处理定时器到期事件。
timer_settime()
使用 struct itimerspec
结构体来设置定时器的初始值和间隔值。它可以设置定时器的绝对时间和相对时间,在定时器到期时执行指定的回调函数,无需注册信号处理函数。
init_timer()
是一个内核函数,用于在内核中初始化定时器。它是用于内核开发的函数,与用户空间的定时器设置无关。它需要在内核模块或驱动程序中使用,用于创建和管理内核定时器。
在内核开发中,可以使用 init_timer()
初始化一个定时器结构体,并将其添加到内核的定时器列表中。然后,可以使用其他函数(如 mod_timer()
)来设置定时器的超时时间和回调函数。
init_timer()
函数与 setitimer()
和 timer_settime()
的主要区别在于它是在内核中使用的,而不是在用户空间中。
选择哪个函数更好取决于具体的需求和开发场景。
setitimer()
就足够了。init_timer()
。timer_settime()
函数来设置定时器。