You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

timer_create返回timer_id为0且timer_settime报无效参数问题排查

问题

使用C++17标准,启动定时器时出现错误提示:Invalid argument。检查发现timer_create()返回0(表示执行成功),但获取到的timer_id值为0,请问这可能是什么问题?


代码

头文件

#pragma once

#include <ctime>
#include <csignal>
#include <cstdint>
#include <functional>
//#include <timerLib.h>

class Timer
{
public:
    Timer(bool periodic = false) : periodic(periodic){}
    ~Timer();
    bool create(void);//Create timer only
    bool create(std::uint64_t timeout);//Create timer, set timeout and start timer
    bool update(std::uint64_t timeout);//Stop timer, update set timeout and start timer
    bool start(std::uint64_t timeout);//Set timeout and start timer
    bool start(void);//Starts the timer with the timeout value (refer private timeout variables)
    bool stop(void);//Stops the timer
    bool destroy(void);//Destroys the timer. Can't be reused without calling create
    using callback_timer_t = std::function<void(void)>;
    void registerCallback(callback_timer_t callback);
private:
    bool                periodic;
    std::uint64_t       timeout;// in nano-seconds
    timer_t             timer_id;
    sigset_t            mask;
    long long           freq_nanosecs;
    struct sigevent     sev;
    struct sigaction    sa;
    struct itimerspec   its;
    static void handler(int sig, siginfo_t *si, void *uc);
    callback_timer_t    callback;
};

源文件

#include "timer.hpp"
#include <iostream>
#include <cstdio>

//The range of supported real-time signals is defined by the macros SIGRTMIN and SIGRTMAX.
//Programs should never refer to real-time signals using hard-coded numbers, but instead should always refer to 
//real-time signals using the notation SIGRTMIN+n, and include suitable (run-time) checks that SIGRTMIN+n 
//does not exceed SIGRTMAX
//the top priority RT signal is SIGRTMIN; the least (lowest) priority RT signal is SIGRTMAX.
//If different real-time signals are sent to a process, they are delivered starting with the lowest-numbered signal. 
//(i.e., low-numbered signals have highest priority.)
#define SIG SIGRTMIN

Timer::~Timer()
{
    this->destroy();
}

bool Timer::create(void)
{
    int returnValue;

    //Establish handler for timer signal.
    this->sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;

    sigemptyset(&this->sa.sa_mask);

    if (sigaction(SIG, &this->sa, nullptr) == -1)
    {
        //Log Error
        perror("sigaction");
        return false;
    }
    //Block timer signal temporarily.   
    printf("Blocking signal %d\n", SIG);
    sigemptyset(&mask);
    sigaddset(&mask, SIG);
    if (sigprocmask(SIG_SETMASK, &this->mask, nullptr) == -1)
    {
        perror("sigprocmask");
        return false;
    }
    //Create a timer
    this->sev.sigev_notify = SIGEV_SIGNAL; //Upon timer expiration, generate the signal sigev_signo for the process.
    this->sev.sigev_signo = SIG;
    this->sev.sigev_value.sival_ptr = this;
    returnValue = timer_create(CLOCK_REALTIME, &this->sev, &this->timer_id);
    std::cout << "Timer Create Return Value : " << returnValue << std::endl;
    if(returnValue == -1)
    {
        //Log Error
        perror("timer_create");
        return false;
    }
    //# -> Used with o, x or X specifiers the value is preceeded with 0, 0x or 0X respectively for values different than zero.
    //j -> The length sub-specifier modifies the length of the data type : uintmax_t
    std::printf("timer ID is %#jx\n", (uintmax_t) timer_id); //Only for testing

    return true;
}

bool Timer::create(std::uint64_t timeout)
{
    bool return_status = this->create();
    if(return_status == false)
    {
        return false;
    }
    return this->start(timeout);
}

bool Timer::update(std::uint64_t timeout)
{
    bool return_status = this->stop();
    if(return_status == false)
    {
        return false;
    }
    return this->start(timeout);
}

bool Timer::start(std::uint64_t timeout)
{
    this->its.it_value.tv_sec = 0;
    this->its.it_value.tv_nsec = timeout;
    if(periodic == true)
    {
        this->its.it_interval.tv_sec = 0;
        this->its.it_interval.tv_nsec = timeout;
    }
    else
    {
        this->its.it_interval.tv_sec = 0;
        this->its.it_interval.tv_nsec = 0;
    }
    return this->start();
}

bool Timer::start(void)
{
    int return_status = timer_settime(this->timer_id, 0, &this->its, nullptr);
    if(return_status == -1)
    {
        //TODO Log Error
        perror("timer_settime");
        return false;
    }
    //TODO Remove in final code
    std::cout << "Timer Started\n";
    return true;
}

bool Timer::stop(void)
{
    struct itimerspec its;
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    int return_status = timer_settime(this->timer_id, 0, &its, nullptr);
    if(return_status == -1)
    {
        //TODO Log Error
        perror("timer_settime");
        return false;
    }
    //TODO Remove in final code
    std::cout << "Timer Stopped\n";
    return true;
}

bool Timer::destroy(void)
{
    int return_status = timer_delete(this->timer_id);
    if(return_status == -1)
    {
        return false;
    }
    else
    {
        return true;
    }
}

void Timer::registerCallback(callback_timer_t callback)
{
    this->callback = callback;
}

void Timer::handler(int sig, siginfo_t *si, void *uc)
{
    Timer *timer = reinterpret_cast<Timer*>(si->si_value.sival_ptr);
    timer->callback();
}

主函数

#include "timer.hpp"
#include <iostream>

void timer_callback(void)
{
    std::cout << "Timeout\n";
}

int main(int argc, char *argv[])
{
    Timer t(true);
    t.registerCallback(timer_callback);
    if(t.create(1000000000ul) == false)
    {
        std::cout << "Timer Create Failed.\tExitting Application.\n";
        return -1;
    }
    while (true)
    {
        /* code */
    }
    
    return 0;
}

输出结果

Blocking signal 34
Timer Create Return Value : 0
timer ID is 0
timer_settime: Invalid argument
Timer Create Failed.    Exitting Application.

CMakeLists.txt

cmake_minimum_required(VERSION 3.6.2)
 
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
 
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

project(timer_lib C CXX ASM)
 
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -g")
 
SET(MY_TARGET ${PROJECT_NAME}.out)
 
add_executable(${MY_TARGET}
    main.cpp
    timer.cpp
)

问题分析与解决

1. timer_id为0的合法性

在Linux系统中,timer_t本质是文件描述符,0是合法值(对应标准输入),timer_create返回0说明定时器创建成功,这个值本身没有问题,无需纠结。

2. timer_settime报错的核心原因

你传入的超时时间是1000000000ul(1秒),但代码中直接将其赋值给tv_nsec,而tv_nsec的取值范围是0到999,999,999,超过这个值会触发EINVAL错误(即Invalid argument)。

3. 修复方案

(1)修正超时时间拆分逻辑

修改start(uint64_t timeout)方法,将纳秒数拆分为秒和纳秒两部分:

bool Timer::start(std::uint64_t timeout)
{
    this->its.it_value.tv_sec = timeout / 1000000000;
    this->its.it_value.tv_nsec = timeout % 1000000000;
    if(periodic == true)
    {
        this->its.it_interval.tv_sec = this->its.it_value.tv_sec;
        this->its.it_interval.tv_nsec = this->its.it_value.tv_nsec;
    }
    else
    {
        this->its.it_interval.tv_sec = 0;
        this->its.it_interval.tv_nsec = 0;
    }
    return this->start();
}

(2)修复信号屏蔽的逻辑错误

在create()方法中,你操作了局部变量mask,但传给sigprocmask的是成员变量this->mask,导致信号屏蔽未正确生效。修改为:

//Block timer signal temporarily.   
printf("Blocking signal %d\n", SIG);
sigemptyset(&this->mask);
sigaddset(&this->mask, SIG);
if (sigprocmask(SIG_SETMASK, &this->mask, nullptr) == -1)

4. 验证

修改后重新编译运行,timer_settime将不再报错,定时器会正常触发回调。


内容的提问来源于stack exchange,提问作者Dark Sorrow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:32:02