如何在 C 中使用 SIGEV_THREAD、sigevent 进行 linux-timer(s) 过期处理?
How to use SIGEV_THREAD, sigevent for linux-timer(s) expiration handling in C?
问题:我有定时器运行,定时器到期后需要调用某些函数。
输出:Hndlr() 函数中存在段错误
根据 sigevent 的手册页,它说,
SIGEV_THREAD - Notify the process by invoking sigev_notify_function "as if" it
were the start function of a new thread. (Among the implement‐
tation possibilities here are that each timer notification
could result in the creation of a new thread, or that a single
thread is created to receive all notifications.)
The function (sigev_notify_function) is invoked with sigev_value as its sole argument
我确实提到了这个:UNIX/Linux signal handling: SIGEV_THREAD 它说,
sigev_value contains supplementary data that is passed to the function
所以,我写了以下内容,
typedef struct Info
{
enum Status
{
Start = 1,
Expire = 2
} TimerStatus;
int data;
timer_t timerId;
} Info_t;
void Hndlr(union sigval *sv)
{
//Upon expiry I want to set this value of t1.TimerStatus Expire:
//t1.TimerStatus = Expire;
//So I have done this:
sv->sival_int = Expire;
}
int TimerInit(Info_t *Type)
{
struct sigevent sev;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_value.sival_ptr = Type->timerId;
sev.sigev_value.sival_int = Type->TimerStatus;
sev.sigev_notify_function = &Hndlr;
sev.sigev_notify_attributes = 0;
timer_create(CLOCK_REALTIME, &sev, &(Type->timerId));
}
//other code
int main(int argc, char const *argv[])
{
Info_t t1;
t1.TimerStatus = Start;
TimerInit(&t1);
//start timer
//other code
while (1)
{
if (t1.TimerStatus == Expire)
{
//do something, invoke a function
}
}
return 0;
}
Warning: assignment to ‘void (*)(__sigval_t)’ {aka ‘void (*)(union sigval)’} from
incompatible pointer type ‘void (*)(union sigval *)’ [-Wincompatible-pointer-types]
sev.sigev_notify_function = &Hndlr;
因为我在 Hndlr 中使用 union sigval *sv,所以我收到了这个警告。
Q) 如何将枚举类型作为 pass-by-ptr 传递给 Hndlr 并更改它,即 t1.TimerStatus = Expire
PS:涉及timer_set()等的全部代码我没有包括在内,而且还涉及定时器的多个实例。那么,我怎样才能实现这个功能 (Q)?
代码中的一些错误:
- 定时器到期函数的函数原型错误
Hndlr
。
- 设置
union sigval
的所有成员,而必须设置一个成员。
- 在另一个线程中修改和读取的变量必须是原子的。
一个工作示例(编译器选项 -std=c11 -pthread -W{all,extra}
、链接器选项 -std=c11 -pthread -lrt
):
#include <stdatomic.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
enum Status {
Start = 1,
Expire = 2
};
typedef struct {
atomic_int status;
int data;
timer_t timerId;
} Info_t;
static void Hndlr(union sigval sigev_value) {
Info_t* info = sigev_value.sival_ptr;
atomic_store(&info->status, Expire);
}
void TimerInit(Info_t* info, unsigned seconds) {
int r;
struct sigevent sev;
struct itimerspec its;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_value.sival_ptr = info;
sev.sigev_notify_function = &Hndlr;
sev.sigev_notify_attributes = 0;
r = timer_create(CLOCK_REALTIME, &sev, &info->timerId);
if(r)
abort();
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
its.it_value.tv_sec = seconds;
its.it_value.tv_nsec = 0;
r = timer_settime(info->timerId, 0, &its, NULL);
if(r)
abort();
}
int main() {
Info_t t1;
t1.status = Start;
TimerInit(&t1, 3);
while(atomic_load(&t1.status) != Expire)
;
return 0;
}
在这个特定的用法中,当计时器回调函数只是存储到一个变量中时,不需要使用另一个线程 SIGEV_THREAD
,SIGEV_SIGNAL
也可以工作(设置代码更改是必需的),只要可以用信号句柄 EINTR
.
中断的阻塞函数
问题:我有定时器运行,定时器到期后需要调用某些函数。 输出:Hndlr() 函数中存在段错误
根据 sigevent 的手册页,它说,
SIGEV_THREAD - Notify the process by invoking sigev_notify_function "as if" it were the start function of a new thread. (Among the implement‐ tation possibilities here are that each timer notification could result in the creation of a new thread, or that a single thread is created to receive all notifications.)
The function (sigev_notify_function) is invoked with sigev_value as its sole argument
我确实提到了这个:UNIX/Linux signal handling: SIGEV_THREAD 它说,
sigev_value contains supplementary data that is passed to the function
所以,我写了以下内容,
typedef struct Info
{
enum Status
{
Start = 1,
Expire = 2
} TimerStatus;
int data;
timer_t timerId;
} Info_t;
void Hndlr(union sigval *sv)
{
//Upon expiry I want to set this value of t1.TimerStatus Expire:
//t1.TimerStatus = Expire;
//So I have done this:
sv->sival_int = Expire;
}
int TimerInit(Info_t *Type)
{
struct sigevent sev;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_value.sival_ptr = Type->timerId;
sev.sigev_value.sival_int = Type->TimerStatus;
sev.sigev_notify_function = &Hndlr;
sev.sigev_notify_attributes = 0;
timer_create(CLOCK_REALTIME, &sev, &(Type->timerId));
}
//other code
int main(int argc, char const *argv[])
{
Info_t t1;
t1.TimerStatus = Start;
TimerInit(&t1);
//start timer
//other code
while (1)
{
if (t1.TimerStatus == Expire)
{
//do something, invoke a function
}
}
return 0;
}
Warning: assignment to ‘void (*)(__sigval_t)’ {aka ‘void (*)(union sigval)’} from
incompatible pointer type ‘void (*)(union sigval *)’ [-Wincompatible-pointer-types]
sev.sigev_notify_function = &Hndlr;
因为我在 Hndlr 中使用 union sigval *sv,所以我收到了这个警告。
Q) 如何将枚举类型作为 pass-by-ptr 传递给 Hndlr 并更改它,即 t1.TimerStatus = Expire
PS:涉及timer_set()等的全部代码我没有包括在内,而且还涉及定时器的多个实例。那么,我怎样才能实现这个功能 (Q)?
代码中的一些错误:
- 定时器到期函数的函数原型错误
Hndlr
。 - 设置
union sigval
的所有成员,而必须设置一个成员。 - 在另一个线程中修改和读取的变量必须是原子的。
一个工作示例(编译器选项 -std=c11 -pthread -W{all,extra}
、链接器选项 -std=c11 -pthread -lrt
):
#include <stdatomic.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
enum Status {
Start = 1,
Expire = 2
};
typedef struct {
atomic_int status;
int data;
timer_t timerId;
} Info_t;
static void Hndlr(union sigval sigev_value) {
Info_t* info = sigev_value.sival_ptr;
atomic_store(&info->status, Expire);
}
void TimerInit(Info_t* info, unsigned seconds) {
int r;
struct sigevent sev;
struct itimerspec its;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_value.sival_ptr = info;
sev.sigev_notify_function = &Hndlr;
sev.sigev_notify_attributes = 0;
r = timer_create(CLOCK_REALTIME, &sev, &info->timerId);
if(r)
abort();
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
its.it_value.tv_sec = seconds;
its.it_value.tv_nsec = 0;
r = timer_settime(info->timerId, 0, &its, NULL);
if(r)
abort();
}
int main() {
Info_t t1;
t1.status = Start;
TimerInit(&t1, 3);
while(atomic_load(&t1.status) != Expire)
;
return 0;
}
在这个特定的用法中,当计时器回调函数只是存储到一个变量中时,不需要使用另一个线程 SIGEV_THREAD
,SIGEV_SIGNAL
也可以工作(设置代码更改是必需的),只要可以用信号句柄 EINTR
.