浅析Linux中的时间编程和实现原理(一) 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 表示通知方式,有如下几种: 如果采用 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: (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |