c++ - POSIX 计时器信号未在信号处理程序中被阻止

标签 c++ c posix signals

我正在设置一个 POSIX 定时器以给定的速率调用一个函数。我设置了一个信号处理程序并初始化了定时器,等等……一切正常。然而,根据我读过的所有文档,当我在信号处理程序中时,我不应该从计时器接收到信号(它应该自动被阻止)。为了更进一步,我什至将 sigaction 的 sa_mask 设置为阻止所有信号......我仍然多次调用信号处理程序......

设置处理程序:

    // establish the signal handler
    sigset_t blockMask;
    struct sigaction sigact;

    sigfillset(&blockMask);
    //sigemptyset(&blockMask);
    sigact.sa_flags = SA_SIGINFO;
    sigact.sa_sigaction = callbackIn;
    sigact.sa_mask = blockMask;
    if( sigaction(ElmoSynchronizer::NEXT_RT_SIGNAL_NUMBER, &sigact, NULL) == -1 )
    {
        return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't establish signal handler for timer" );   
    }

    // create the timer
    struct sigevent sev;
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = ElmoSynchronizer::NEXT_RT_SIGNAL_NUMBER;
    sev.sigev_value.sival_ptr = this;
    if( timer_create(CLOCK_REALTIME, &sev, timerIn) == -1 )
    {
        return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't create POSIX timer for timer" );
    }

    // start the timer
    struct itimerspec timerSpec;
    timerSpec.it_value = firstExecTime;
    timerSpec.it_interval = ElmoSynchronizer::getTimespecFromDouble(1.0/rate_hz);
    if( timer_settime(*timerIn, TIMER_ABSTIME, &timerSpec, NULL) == -1 )
    {
        return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't start timer for timer" );
    }

回调(是的,我知道 printfs 在信号处理程序中很糟糕):

 void ElmoSynchronizer::rootPvtCallback(int sig, siginfo_t *si, void *uc)
{

    // get a pointer to the ElmoSynchronizer calling this
    ElmoSynchronizer *elmoSync = (ElmoSynchronizer*)si->si_value.sival_ptr;

    struct timespec startTime;
    clock_gettime(CLOCK_REALTIME, &startTime);
    uint32_t expectedTime_us = elmoSync->getMasterClockTimeFromTimespec_us(elmoSync->m_pvtSupplyStartTime) + ((elmoSync->m_updateIteration * elmoSync->m_elmoUpdatePeriod_ms) * 1000);
    uint32_t actualTime_us = elmoSync->getMasterClockTimeFromTimespec_us(startTime);
    uint32_t currIter = elmoSync->m_updateIteration+1;

    printf("---> PVT update - iteration %u @ %u\n", currIter, elmoSync->getMasterClockTimeFromTimespec_us(startTime));
    fflush(stdout);

    // iterate through all of our callbacks and call them!
    for( unsigned int i = 0; i < elmoSync->m_elmos.size(); i++ )
    {
        // get the position/velocity pair
        posVelPair_t pv = elmoSync->m_elmos[i].callback(elmoSync->m_elmos[i].elmo);

        // now add the point to the elmo
        elmoSync->m_elmos[i].elmo->addPvtPoints( pv.position_cnts, pv.velocity_cps, elmoSync->m_elmoUpdatePeriod_ms );

    }
    elmoSync->m_updateIteration++;

    if( elmoSync->m_updateIteration == 250 )
    {
        usleep(elmoSync->m_elmoUpdatePeriod_ms*4000);
    }

    // make sure we executed fast enough   
    struct timespec endTime;
    clock_gettime(CLOCK_REALTIME, &endTime);
    double totalCallbackTime_s = getSecondsFromTimespec(ElmoSynchronizer::ts_subtract(endTime, startTime));
    if( totalCallbackTime_s > (elmoSync->m_elmoUpdatePeriod_ms * 1.0E-3) )
    {
        //ROS_WARN("PVT update - Callback execution took longer than update period! %lfs actual / %lfs period", totalCallbackTime_s, (elmoSync->m_elmoUpdatePeriod_ms * 1.0E-3));
        //overflowedRootPvtCallbackPeriod = true;
    }

    printf("<--- PVT update - iteration %u @ %u\n", currIter, elmoSync->getMasterClockTimeFromTimespec_us(endTime));
    fflush(stdout);

    /*
    printf("PVT update - iteration: %u actual: %u expected: %u diff: %u cbTime: %u\n",
        elmoSync->m_updateIteration, actualTime_us, expectedTime_us, actualTime_us-expectedTime_us, (uint32_t)(totalCallbackTime_s * 1.0E6));
    fflush(stdout);
    */
}

输出:

---> PVT update - iteration 248 @ 13315103
<--- PVT update - iteration 248 @ 13315219
---> PVT update - iteration 249 @ 13346107
<--- PVT update - iteration 249 @ 13346199
---> PVT update - iteration 250 @ 13377104    // two entrances
---> PVT update - iteration 251 @ 13408109    // second entrance
<--- PVT update - iteration 251 @ 13408197
---> PVT update - iteration 252 @ 13439109
<--- PVT update - iteration 252 @ 13439254
---> PVT update - iteration 253 @ 13470120
<--- PVT update - iteration 253 @ 13470216
---> PVT update - iteration 254 @ 13501122
<--- PVT update - iteration 254 @ 13501213
<--- PVT update - iteration 250 @ 13501317    // exit for iteration 250
---> PVT update - iteration 255 @ 13532078
<--- PVT update - iteration 255 @ 13532170
---> PVT update - iteration 256 @ 13563109
<--- PVT update - iteration 256 @ 13563242

最佳答案

不是设置周期性定时器,而是在信号处理程序结束时再次触发。

创建计时器时执行此操作

// start the timer
//struct itimerspec timerSpec;
this->timerSpec_.it_value = firstExecTime;
this->timerSpec_.it_interval = 0; //one-shot 
if( timer_settime(*timerIn, TIMER_ABSTIME, &this->timerSpec_, NULL) == -1 )
{
    return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't start timer for timer" );
}

// from now we will shoot the timer with this value
this->timerSpec_.it_value = ElmoSynchronizer::getTimespecFromDouble(1.0/rate_hz);

// store *timerIn in also in ElmoSynchronizer
this->timerId_ = *timerIn;

然后将此附加到 ElmoSynchronizer::rootPvtCallback 函数的末尾

//shoot our the timer again
if( timer_settime(elmoSync->timerId_, 0, &elmoSync->timerSpec_, NULL) == -1 )
{
    return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't restart timer" );
}

顺便说一下,我会用线程和信号量来完成整个事情,这样同步器就可以简单地检查 PVT 更新过程是否在定义的持续时间内结束。 POSIX 提供了它们并且并不比计时器更难实现。

关于c++ - POSIX 计时器信号未在信号处理程序中被阻止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4514011/

相关文章:

c++ - Unresolved external symbol 错误(VS2013 Express)

c - 我应该如何继续这段代码?本作业的第二部分应该使用什么关键字?

bash - 仅使用 Bash 模式匹配从字符串开头删除模式

c++ - 如何转换 C++ 模板参数?

c++ - 双重简单的 for 循环与一个复杂的循环

c++ - 使用 placement new、malloc 和 free

c - 将数组作为参数传递给 C 中的函数

c - 如何在 C 中实现位集?

c++ - 如何关闭cerr

c - 是否应该从 main() 返回或调用 exit() 禁用线程取消?