定时器小结 setitimer/getitimer Or timer_settime/timer_gettime

本文介绍了在将Python移植到VxWorks过程中遇到的定时器问题。Linux中使用setitimer和getitimer,而VxWorks则支持timer_settime和timer_gettime。文章详细解析了两者之间的区别,包括参数、功能和用法,指出在VxWorks中应当使用POSIX定时器函数timer_settime/timer_gettime来替代setitimer/getitimer,并提到了创建和删除定时器的相关函数。

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

    最近在移植Python至VxWorks,小小菜鸟遇到了粉多麻烦,其中定时器相关的就可独占一章。

    首先,对于定时器中使用的数据结构,在Python中使用的数据结构为itimerval,通过查阅VxWorks手册及源码可知,VxWorks支持的数据结构为itimerspec,如下:

    itimerval结构在UNIX/LINUX中定义,定义如下:

Struct itimerval{

Struct timeval it_interval; /* nextvalue:下一次触发所需的时间*/

Struct timeval it_value;  /*current value:目前距离触发时间点剩余的时间*/

};

Struct timeval{

Long tv_sec; /* seconds */

Long tv_usec; /*microseconds*/

};

    查阅VxWorks源码后认为,该数据结构与VxWorks中的itimespec结构意义相同,该结构在time.h中定义,VxWorks中定义如下:

structitimerspec

{

    struct timespecit_interval;        /* timer period(reload value) */

    struct timespecit_value;                /*timer expiration */

};

structtimespec

{                                           /*interval = tv_sec*10**9 + tv_nsec */

    time_t tv_sec;                        /*seconds */

    long tv_nsec;                        /*nanoseconds (0 - 1,000,000,000) */

};

    修改完毕并编译APP通过后下载时出现问题,提示_setitimer, _getitimer符号出错,原来python代码中定时器使用的是setitimer和getitimer函数,显然,这两个函数在VxWorks系统中是不支持的,不仅手册中没有该函数介绍,就连VxWorks源码中说明setitimer的地方实际使用的也是timer_settime函数。

1 setitimer()/getitimer()

Setitimer/getitimer为Linux的API,并非C语言的标准库。函数定义为:

#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value));

intgetitimer(int which, struct itimerval *curr_value);

其中,

getitimer获取which指定的定时器的值并填入curr_value字段中。

setitimer设定指定的定时器,即设置vlaue的值。各参数说明如下:

第一个参数:which为定时器类型,setitimer支持3种类型的定时器:

ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。

ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。 (

decrements only when the process is executing, anddelivers SIGVTALRM upon expiration

ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。(

decrements both when the process executes and when thesystem is executing on behalf of the process. Coupled with ITIMER_VIRTUAL, this timer is usually usedto profile the time spent by the application in user and kernel space. SIGPROF is delivered upon expiration.

第二个参数:new_value,表示设定的定时器值;

第三个参数:old_value ,常设为NULL,如果不为NULL,用来保存先前的定时器值,

返回值:调用成功返回0,否则返回-1

说明:setitimer()基于进程,且不由fork()继承而来。(A child created via fork(2) does not inherit its parent's interval timers.Interval timers are preserved across an execve(2).

POSIX.1 leaves the interaction between setitimer() and the three interfaces alarm(2), sleep(3), and usleep(3) unspecified.

Bugs

The generation and delivery of a signal are distinct, and only oneinstance of each of the signals listed above may be pending for a process.Under very heavy loading, an ITIMER_REALtimer may expire before the signal from a previous expiration has beendelivered. The second signal in such an event will be lost.

On Linux kernels before 2.6.16, timer values are represented injiffies. If a request is made set a timer with a value whose jiffiesrepresentation exceeds MAX_SEC_IN_JIFFIES(defined in include/linux/jiffies.h),then the timer is silently truncated to this ceiling value. On Linux/i386(where, since Linux 2.6.13, the default jiffy is 0.004 seconds), this meansthat the ceiling value for a timer is approximately 99.42 days. Since Linux2.6.16, the kernel uses a different internal representation for times, and thisceiling is removed.

On certain systems (including i386), Linux kernels before version2.6.12 have a bug which will produce premature timer expirations of up to onejiffy under some circumstances. This bug is fixed in kernel 2.6.12.

POSIX.1-2001 says that setitimer() should fail if a tv_usecvalue is specified that is outside of the range 0 to 999999. However, inkernels up to and including 2.6.21, Linux does not give an error, but insteadsilently adjusts the corresponding seconds value for the timer. From kernel2.6.22 onward, this nonconformance has been repaired: an improper tv_usec value results in an EINVAL error.

源文档 <http://linux.die.net/man/2/setitimer>

 

2, timer_settime/timer_gettime

VxWorks系统中支持的定时器函数为timer_settime/timer_gettime, 这两个函数是POSIX定时器,在POSIX系统中应使用该函数替代上面说的setitimer/getitimer。函数定义如下:

#include <time.h>

int timer_settime(timer_t timerid, int flags,
                  const struct itimerspec*new_value,
                  struct itimerspec *old_value);
int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
Timer_settime() arms ordisarms 由timerid指定的定时器。参数取值如下:

第一个参数:timerid, 指定定时器ID;

第二个参数:flags,定时器类型,取值可为TIMER_ABSTIME/CLOCK_REALTIME。

说明:

By default, the initial expiration time specified in new_value->it_value is interpreted relative to the current time on the timer'sclock at the time of the call. This can be modified by specifying TIMER_ABSTIME in flags, in which case new_value->it_value isinterpreted as an absolute value as measured on the timer's clock; that is, thetimer will expire when the clock value reaches the value specified by new_value->it_value. If the specified absolute time has already passed, thenthe timer expires immediately, and the overrun count (see timer_getoverrun(2)) will be setcorrectly.

If the value of the CLOCK_REALTIMEclock is adjusted while an absolute timer based on that clock is armed, thenthe expiration of the timer will be appropriately adjusted. Adjustments to the CLOCK_REALTIME clock have no effect on relativetimers based on that clock.

第三个参数:new_value, 指定定时器的新初始值和间隔;

第四个参数:old_value, 取值常为NULL,若不为NULL,它返回定时器的前一个值。(

previous interval of the timer (in old_value->it_interval) and the amount of time until thetimer would previously have next expired (in old_value->it_value).

Timer_gettime返回定时器截止的时间,说明如下:

timer_gettime() returns thetime until next expiration, and the interval, for the timer specified by timerid, in the buffer pointed to by curr_value. The time remaining until the nexttimer expiration is returned in curr_value->it_value;this is always a relative value, regardless of whether the TIMER_ABSTIME flag was used when arming thetimer. If the value returned in curr_value->it_valueis zero, then the timer is currently disarmed. The timer interval is returnedin curr_value->it_interval. If thevalue returned in curr_value->it_intervalis zero, then this is a "one-shot" timer.

返回值:

On success, timer_settime()and timer_gettime() return 0. On error,-1 is returned, and errno is set toindicate the error.

源文档 <http://linux.die.net/man/2/timer_gettime>

 

说明:在使用定时器前,需要先创建定时器(timer_create),使用完定时器后,还需删除定时器。

#include<signal.h>
#include <time.h>

inttimer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);

函数功能:为进程创建一个新定时器。

参数说明:

第一个参数:clockid, 指定新定时器用于度量时间的始终,可以为下列值:

CLOCK_REALTIME

A settable system-wide real-time clock.

CLOCK_MONOTONIC

A nonsettable monotonically increasing clock thatmeasures time from some unspecified point in the past that does not changeafter system startup.

CLOCK_PROCESS_CPUTIME_ID(since Linux 2.6.12)

A clock that measures (user and system) CPU timeconsumed by (all of the threads in) the calling process.

CLOCK_THREAD_CPUTIME_ID (sinceLinux 2.6.12)

A clock that measures (user and system) CPU timeconsumed by the calling thread

第二个参数:sevp,指定当定时器时间到期时触发的信号事件sigevent,sevp.sigev_notify取值如下:

SIGEV_NONE

Don't asynchronously notify when the timerexpires. Progress of the timer can be monitored using timer_gettime(2).

SIGEV_SIGNAL

Upon timer expiration, generate the signalsigev_signo for the process. See sigevent(7) for general details. The si_code field of the siginfo_tstructure will be set to SI_TIMER. At any point in time, at most one signal is queued to theprocess for a given timer; see timer_getoverrun(2) for moredetails.

SIGEV_THREAD

Upon timer expiration, invoke sigev_notify_function as if it were the start function of a new thread. See sigevent(7) for details.

SIGEV_THREAD_ID(Linux-specific)

As for SIGEV_SIGNAL, but the signalis targeted at the thread whose ID is given in sigev_notify_thread_id,which must be a thread in the same process as the caller. The sigev_notify_thread_id field specifies a kernel thread ID, that is, the valuereturned by clone(2) or gettid(2). This flag is only intended for use by threadinglibraries.

Specifying sevpas NULL is equivalent to specifying a pointer to a sigevent structure in which sigev_notifyis SIGEV_SIGNAL, sigev_signo is SIGALRM,and sigev_value.sival_int is the timerID

第三个参数:timerid,定时器ID,为函数返回值,必须是一个非空的指针,且在进程中唯一。

返回值:
Onsuccess, timer_create() returns 0, and the ID of the newtimer is placed in *timerid. On failure, -1 is returned,and errno is set to indicate the error

源文档 <http://linux.die.net/man/2/timer_create>

 

在 Linux 系统中,`timer_t` 是用于表示定时器对象的句柄,它是 POSIX 定时器接口的一部分。`timer_t` 类型通常用于支持高精度定时任务的场景,例如需要定时执行某些操作或在特定时间点触发事件。与传统的 `alarm()` 或 `setitimer()` 相比,`timer_t` 提供了更灵活的定时控制,支持多种时钟源、异步通知机制以及多个定时器的同时管理。 `timer_t` 的使用通常涉及以下几个关键函数: - `timer_create()`:创建一个定时器对象。 - `timer_settime()`:设置定时器的初始值和间隔。 - `timer_gettime()`:获取定时器的当前值。 - `timer_delete()`:删除定时器。 ### 编程示例 以下是一个使用 `timer_t` 的简单示例。该示例创建一个定时器,并在定时器到期时通过信号通知应用程序: ```c #include <stdio.h> #include <signal.h> #include <time.h> #include <unistd.h> #define CLOCKID CLOCK_REALTIME timer_t timerid; struct sigevent sev; struct itimerspec its; void handler(int sig, siginfo_t *si, void *uc) { if (si->si_value.sival_ptr == &timerid) printf("Caught timer signal\n"); } int main(void) { struct sigaction sa; // 建立信号处理程序 sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); sigaction(SIGRTMIN, &sa, NULL); // 设置信号事件 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCKID, &sev, &timerid); // 设置定时器初始值和间隔 its.it_value.tv_sec = 2; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; its.it_interval.tv_nsec = 0; timer_settime(timerid, 0, &its, NULL); printf("Timer started, waiting for signals...\n"); while (1) pause(); return 0; } ``` 该程序创建了一个定时器,初始延迟为 2 秒,之后每 1 秒触发一次信号 `SIGRTMIN`,并在信号处理函数中打印相关信息。 ### 使用场景 - **实时系统**:适用于需要精确控制定时行为的实时应用程序。 - **异步通知**:支持通过信号、线程函数等方式进行异步回调。 - **多定时器管理**:可同时管理多个定时器实例,适用于复杂调度逻辑。 ### 注意事项 - `timer_t` 的精度依赖于系统所使用的时钟源,例如 `CLOCK_REALTIME` 或 `CLOCK_MONOTONIC`。 - 在使用 `timer_create()` 时,需注意信号处理函数的安全性,避免在信号处理中调用非异步信号安全函数。 - 定时器在使用完毕后应调用 `timer_delete()` 释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值