Sigevent 计时器无法重新启动,也无法执行回调
Sigevent timer can't be restarted nor it executes a callback
我有一个 t_timer 设置,使用 struct sigevent 和 struct itimerspec 为 6 秒。
如果某个事件发生,我的程序应该刷新这个计时器,否则,在计时器到期时,应该执行回调,最后程序应该停止
然而,不仅回调被完全忽略,而且我无法重新启动所述计时器。
以下是一些前奏代码,其中使用了我class中的变量。我尽量缩短和简化代码。
typedef struct itimerspec TTL;
typedef struct sigevent handler;
struct RtnodeSpvSession : public rtnode::SessionInterface {
boost::asio::io_service iSvc;
timer_t tTimer;
TTL tTimerSetter;
void OnStart();
void EnqueueRead();
void Thread_TTL();
void ResetTTL;
}
void RtnodeSpvSession::OnStart()
{
printf("Starting RtnodeSpvSession...\n");
TTL_Thread();
iSvc.post(boost::bind(&RtnodeSpvSession::EnqueueRead, this));
}
EnqueueRead 每 x 秒调用一次,if 语句检查确定是否必须重置计时器的条件
void RtnodeSpvSession::EnqueueRead()
{
if (1<2)
{
ResetTTL();
}
else
{
//do nothing
}
}
sigevent.At 计时器过期的回调方法此字符串从未被打印,也似乎根本没有调用该方法
static void catch_alarm(union sigval sv)
{
std::cout << "Imma dead\n\n\n\n";
}
最后创建计时器
void RtnodeSpvSession::TTL_Thread()
/**
* Starts the timeout timer
* When tTimerSetter expires, tTimeoutHandler executes the callback on method catch_alarm
* and triggers the process kill
*/
{
handler tTimeoutHandler;
tTimeoutHandler.sigev_notify = SIGEV_THREAD_ID; /* Notify via thread */
tTimeoutHandler.sigev_notify_function = catch_alarm; /* Thread start function */
tTimeoutHandler._sigev_un._tid = syscall(SYS_gettid);
tTimeoutHandler.sigev_signo = SIGHUP;
tTimeoutHandler.sigev_notify_attributes = NULL;
if (timer_create(CLOCK_REALTIME, &tTimeoutHandler, &tTimer) == -1) {
perror("timer_create");
exit(1);
}
memset(&tTimerSetter,0,sizeof(tTimerSetter));
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_sec = 6;
tTimerSetter.it_interval.tv_nsec = 0;
tTimerSetter.it_interval.tv_sec = 0;
if (timer_settime(tTimer, 0, &tTimerSetter, NULL) == -1) {
perror("timer_settime");
exit(1);
}
}
这是我明显有缺陷的重置:我认为从头开始删除并重新创建计时器是我的下一个最佳选择,因为我无法直接操作现有计时器。但是没用。
void RtnodeSpvSession::ResetTTL()
/// Resets the process's TTL
{
std::cout << "BEGINNING RESET\n\n\n";
timer_delete(tTimer);
TTL_Thread();
}
我找到了一些关于这个的东西。如果使用SIGEV_THREAD_ID
,定时器会向线程id发送一个信号。所以你必须在线程中安装一个信号处理程序,函数 catch_alarm
不会被调用,只是信号处理程序,但在线程中。
如果您使用 SIGEV_THREAD
,那么函数 catch_alarm
将被调用,但是您不能设置线程 ID,因为它会以您的名义创建。
以下代码如您所愿:
typedef struct itimerspec TTL;
typedef struct sigevent handler;
void catch_alarm(union sigval sv)
{
//std::cout << "Imma dead\n\n\n\n";
printf ("\nSignaled in %d = %d\n\n", syscall(SYS_gettid), sv.sival_int);
for (int i = 0; i < 5; ++i) {
printf ("Process in thread %d\n", i);
sleep(1);
}
}
int main ()
{
timer_t tTimer;
TTL tTimerSetter;
handler tTimeoutHandler;
printf ("My pid: %d %d\n", getpid(), syscall(SYS_gettid));
memset(&tTimeoutHandler,0,sizeof(tTimeoutHandler));
tTimeoutHandler.sigev_notify = SIGEV_THREAD; /* Notify via thread */
tTimeoutHandler.sigev_notify_function = catch_alarm; /* Thread start function */
tTimeoutHandler.sigev_value.sival_int = 9999;
tTimeoutHandler.sigev_notify_attributes = NULL;
printf ("Creating timer\n");
if (timer_create(CLOCK_REALTIME, &tTimeoutHandler, &tTimer) == -1) {
perror("timer_create");
exit(1);
}
memset(&tTimerSetter,0,sizeof(tTimerSetter));
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_sec = 5;
tTimerSetter.it_interval.tv_nsec = 0;
tTimerSetter.it_interval.tv_sec = 0;
if (timer_settime(tTimer, 0, &tTimerSetter, NULL) == -1) {
perror("timer_settime");
exit(1);
}
printf ("To wait\n");
for (int i = 0; i < 10; ++i) {
printf ("Waiting %d\n", i);
sleep(1);
}
printf ("Finished\n");
return 0;
}
输出:
My pid: 27473 27473
Creating timer
To wait
Waiting 0
Waiting 1
Waiting 2
Waiting 3
Waiting 4
Signaled in 27477 = 9999
Process in thread 0
Waiting 5
Process in thread 1
Waiting 6
Process in thread 2
Waiting 7
Process in thread 3
Waiting 8
Process in thread 4
Waiting 9
Waiting 10
Waiting 11
Waiting 12
Waiting 13
Waiting 14
Finished
SIGEV_THREAD_ID (Linux-specific)
As for SIGEV_SIGNAL, but the signal is targeted at the thread whose ID is given in sigev_notify_thread_id
关键:至于SIGEV_SIGNAL.
如前所述,如果您使用 SIGEV_THREAD_ID
,则必须创建线程,并且 信号 将发送到该线程。
我有一个 t_timer 设置,使用 struct sigevent 和 struct itimerspec 为 6 秒。
如果某个事件发生,我的程序应该刷新这个计时器,否则,在计时器到期时,应该执行回调,最后程序应该停止
然而,不仅回调被完全忽略,而且我无法重新启动所述计时器。
以下是一些前奏代码,其中使用了我class中的变量。我尽量缩短和简化代码。
typedef struct itimerspec TTL;
typedef struct sigevent handler;
struct RtnodeSpvSession : public rtnode::SessionInterface {
boost::asio::io_service iSvc;
timer_t tTimer;
TTL tTimerSetter;
void OnStart();
void EnqueueRead();
void Thread_TTL();
void ResetTTL;
}
void RtnodeSpvSession::OnStart()
{
printf("Starting RtnodeSpvSession...\n");
TTL_Thread();
iSvc.post(boost::bind(&RtnodeSpvSession::EnqueueRead, this));
}
EnqueueRead 每 x 秒调用一次,if 语句检查确定是否必须重置计时器的条件
void RtnodeSpvSession::EnqueueRead()
{
if (1<2)
{
ResetTTL();
}
else
{
//do nothing
}
}
sigevent.At 计时器过期的回调方法此字符串从未被打印,也似乎根本没有调用该方法
static void catch_alarm(union sigval sv)
{
std::cout << "Imma dead\n\n\n\n";
}
最后创建计时器
void RtnodeSpvSession::TTL_Thread()
/**
* Starts the timeout timer
* When tTimerSetter expires, tTimeoutHandler executes the callback on method catch_alarm
* and triggers the process kill
*/
{
handler tTimeoutHandler;
tTimeoutHandler.sigev_notify = SIGEV_THREAD_ID; /* Notify via thread */
tTimeoutHandler.sigev_notify_function = catch_alarm; /* Thread start function */
tTimeoutHandler._sigev_un._tid = syscall(SYS_gettid);
tTimeoutHandler.sigev_signo = SIGHUP;
tTimeoutHandler.sigev_notify_attributes = NULL;
if (timer_create(CLOCK_REALTIME, &tTimeoutHandler, &tTimer) == -1) {
perror("timer_create");
exit(1);
}
memset(&tTimerSetter,0,sizeof(tTimerSetter));
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_sec = 6;
tTimerSetter.it_interval.tv_nsec = 0;
tTimerSetter.it_interval.tv_sec = 0;
if (timer_settime(tTimer, 0, &tTimerSetter, NULL) == -1) {
perror("timer_settime");
exit(1);
}
}
这是我明显有缺陷的重置:我认为从头开始删除并重新创建计时器是我的下一个最佳选择,因为我无法直接操作现有计时器。但是没用。
void RtnodeSpvSession::ResetTTL()
/// Resets the process's TTL
{
std::cout << "BEGINNING RESET\n\n\n";
timer_delete(tTimer);
TTL_Thread();
}
我找到了一些关于这个的东西。如果使用SIGEV_THREAD_ID
,定时器会向线程id发送一个信号。所以你必须在线程中安装一个信号处理程序,函数 catch_alarm
不会被调用,只是信号处理程序,但在线程中。
如果您使用 SIGEV_THREAD
,那么函数 catch_alarm
将被调用,但是您不能设置线程 ID,因为它会以您的名义创建。
以下代码如您所愿:
typedef struct itimerspec TTL;
typedef struct sigevent handler;
void catch_alarm(union sigval sv)
{
//std::cout << "Imma dead\n\n\n\n";
printf ("\nSignaled in %d = %d\n\n", syscall(SYS_gettid), sv.sival_int);
for (int i = 0; i < 5; ++i) {
printf ("Process in thread %d\n", i);
sleep(1);
}
}
int main ()
{
timer_t tTimer;
TTL tTimerSetter;
handler tTimeoutHandler;
printf ("My pid: %d %d\n", getpid(), syscall(SYS_gettid));
memset(&tTimeoutHandler,0,sizeof(tTimeoutHandler));
tTimeoutHandler.sigev_notify = SIGEV_THREAD; /* Notify via thread */
tTimeoutHandler.sigev_notify_function = catch_alarm; /* Thread start function */
tTimeoutHandler.sigev_value.sival_int = 9999;
tTimeoutHandler.sigev_notify_attributes = NULL;
printf ("Creating timer\n");
if (timer_create(CLOCK_REALTIME, &tTimeoutHandler, &tTimer) == -1) {
perror("timer_create");
exit(1);
}
memset(&tTimerSetter,0,sizeof(tTimerSetter));
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_nsec = 0;
tTimerSetter.it_value.tv_sec = 5;
tTimerSetter.it_interval.tv_nsec = 0;
tTimerSetter.it_interval.tv_sec = 0;
if (timer_settime(tTimer, 0, &tTimerSetter, NULL) == -1) {
perror("timer_settime");
exit(1);
}
printf ("To wait\n");
for (int i = 0; i < 10; ++i) {
printf ("Waiting %d\n", i);
sleep(1);
}
printf ("Finished\n");
return 0;
}
输出:
My pid: 27473 27473
Creating timer
To wait
Waiting 0
Waiting 1
Waiting 2
Waiting 3
Waiting 4
Signaled in 27477 = 9999
Process in thread 0
Waiting 5
Process in thread 1
Waiting 6
Process in thread 2
Waiting 7
Process in thread 3
Waiting 8
Process in thread 4
Waiting 9
Waiting 10
Waiting 11
Waiting 12
Waiting 13
Waiting 14
Finished
SIGEV_THREAD_ID (Linux-specific) As for SIGEV_SIGNAL, but the signal is targeted at the thread whose ID is given in sigev_notify_thread_id
关键:至于SIGEV_SIGNAL.
如前所述,如果您使用 SIGEV_THREAD_ID
,则必须创建线程,并且 信号 将发送到该线程。