问题描述
问题:我正在运行计时器,在计时器到期时,需要调用某些功能。 输出:Hndlr()函数内部存在段错误
根据sigevent的手册页,
SIGEV_THREAD-通过“好像”调用sigev_notify_function来通知进程 是新线程的启动功能。 (在工具中- 这里的可能性是每个计时器通知 可能会导致创建新线程,或者单个 创建线程以接收所有通知。)
我确实提到了这个:UNIX/Linux signal handling: SIGEV_THREAD,上面写着,
sigev_value包含传递给函数的补充数据
所以,我写了以下内容,
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)如何将枚举类型作为点对点传递给Hndlr并进行更改,即t1.TimerStatus = Expire
PS:我没有包括涉及timer_set()等的完整代码,它还涉及到多个timer实例。那么,如何实现此功能(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,&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
中断的阻塞功能即可。