加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

浅析Linux中的时间编程和实现原理(一) Linux应用层的时间编程

发布时间:2016-09-07 14:55:31 所属栏目:Linux 来源:站长网
导读:引子 我们都生活在时间中,但却无法去思考它。什么是时间呢?似乎这是一个永远也不能被回答的问题。然而作为一个程序员,在工作中,总有那么几次我必须思考什么

清单 10,结构 sigevent

struct sigevent {
int sigev_notify; /* Notification method */
int sigev_signo; /* Notification signal */
union sigval sigev_value; /* Data passed with
notification */
void (*sigev_notify_function) (union sigval);
/* Function used for thread
notification (SIGEV_THREAD) */
void *sigev_notify_attributes;
/* Attributes for notification thread
(SIGEV_THREAD) */
pid_t sigev_notify_thread_id;
/* ID of thread to signal (SIGEV_THREAD_ID) */
};

其中 sigev_notify 表示通知方式,有如下几种:

浅析Linux中的时间编程和实现原理(一) Linux应用层的时间编程

如果采用 SIGEV_NONE 方式,使用者必须调用timer_gettime 函数主动读取定时器已经走过的时间。类似轮询。

如果采用 SIGEV_SIGNAL 方式,使用者可以选择使用什么信号,用 sigev_signo 表示信号值,比如 SIG_ALARM。

如果使用 SIGEV_THREAD 方式,则需要设置 sigev_notify_function,当 Timer 到期时,将使用该函数作为入口启动一个线程来处理信号;sigev_value 保存了传入 sigev_notify_function 的参数。sigev_notify_attributes 如果非空,则应该是一个指向 pthread_attr_t 的指针,用来设置线程的属性(比如 stack 大小,detach 状态等)。

SIGEV_THREAD_ID 通常和 SIGEV_SIGNAL 联合使用,这样当 Timer 到期时,系统会向由 sigev_notify_thread_id 指定的线程发送信号,否则可能进程中的任意线程都可能收到该信号。这个选项是 Linux 对 POSIX 标准的扩展,目前主要是 GLibc 在实现 SIGEV_THREAD 的时候使用到,应用程序很少会需要用到这种模式。

启动定时器

创建 Timer 之后,便可以调用 timer_settime() 函数指定定时器的时间间隔,并启动该定时器了。

int timer_settime(timer_t timerid, int flags,

const struct itimerspec *new_value,

struct itimerspec * old_value);

第一次看到 timer_settime 的参数列表或许会令人觉得费解。先来看看 new_value 和 old_value,它们都是 struct itimerspec 数据结构。

struct itimerspec

{

struct timespec it_interval; //定时器周期值

struct timespec it_value; //定时器到期值

};

启动和停止 Timer 都可以通过设置 new_value 来实现:

new_value->it_interval 为定时器的周期值,比如 1 秒,表示定时器每隔 1 秒到期;

new_value->it_value 如果大于 0,表示启动定时器,Timer 将在 it_value 这么长的时间过去后到期,此后每隔 it_interval 便到期一次。如果 it_value 为 0,表示停止该 Timer。

有些时候,应用程序会先启动用一个时间间隔启动定时器,随后又修改该定时器的时间间隔,这都可以通过修改 new_value 来实现;假如应用程序在修改了时间间隔之后希望了解之前的时间间隔设置,则传入一个非 NULL 的 old_value 指针,这样在 timer_settime() 调用返回时,old_value 就保存了上一次 Timer 的时间间隔设置。多数情况下我们并不需要这样,便可以简单地将 old_value 设置为 NULL,忽略它。

下面给出一个使用 posix timer 的例子程序。最传统的例子就是创建通知方式为 SIGEV_SIGNAL 的 Timer。这样当定时器到期时,将产生信号通知,主程序需要定义自己的信号处理函数,来处理信号到期事件。这种例子比比皆是,我打算在这里写一个采用通知方式为 SIGEV_THREAD 的例子。该例子程序从 main 函数开始主线程,在开始的时候打印出主线程的进程 ID 和线程 ID。

清单 11,打印 TID

pid_t tid = (pid_t) syscall (SYS_gettid);

printf("start program in PID:[%d]TID:[%d]n",getpid(),tid);

获得 ThreadID 的系统调用尚未被 GLibC 标准化,因此这里直接调用 syscall。

然后,主线程初始化创建 Timer 所需要的数据结构:

清单 12,设置通知方式

se.sigev_notify = SIGEV_THREAD;

se.sigev_value.sival_ptr = &timer_id;

se.sigev_notify_function = timer_thread;

se.sigev_notify_attributes = NULL;

status = timer_create(CLOCK_REALTIME, &se, &timer_id);

这里将通知方式设为 SIGEV_THREAD,timer_thread 为线程入口函数。

然后主线程设置定时器间隔,并启动 Timer:

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读