POSIX 定时器_QNX实现

一、POSXI接口定时器_QNX实现

设置定时器,并设置通知方式,内核以signal的方式通知到时

#include "Handler.hpp"
#include <iostream>
#include <memory>
#include <ctime>
#include <mutex>
#include <queue>
#ifdef __QNX__
#include <sys/siginfo.h>
#endif

namespace nio
{

    HandlerQueue::HandlerQueue(DispatchQueue &dispatchQueue) : mDispatchQueue(dispatchQueue)
    {
    }
    HandlerQueue::~HandlerQueue()
    {
    }

    void HandlerQueue::pushFunctionDelayed(int msgId, TimerTriggeredFunction &&triggeredFunction, long delayMs)
    {
        Message *msg = new Message(msgId, std::move(triggeredFunction), mDispatchQueue);

        /** 
        设置计时结束后,系统的通知方式,这里设置的是后台另启动一个线程,通过信号方式通知,并调用onTriggered方法,同时将msg指针传给onTriggered。

        SIGEV_THREAD_INIT (eventp, func, val, attributes)
        用线程函数(func)和属性结构(attribute)填充eventp。执行线程时,将val中的值传递给func中的函数。
        **/
        SIGEV_THREAD_INIT(&msg->mEvent, HandlerQueue::onTriggered, msg, 0);
#ifdef __QNX__

        itimerspec itime;

        itime.it_value.tv_sec = delayMs / 1000; //设置秒单位的计时
        itime.it_value.tv_nsec = 1000000 * (delayMs % 1000);//设置纳秒单位的计时
        itime.it_interval.tv_sec = 0; //设置秒单位的计时器间隔
        itime.it_interval.tv_nsec = 0;//设置纳秒单位的计时器间隔

        /**
         * #include <time.h>
           #include <sys/siginfo.h>
            int timer_create (clockid_t clock_id,
                        struct sigevent *event,
                        timer_t *timerid);

                        该clock_id参数告诉timer_create()函数它要创建这个定时器时间基准。这是POSIX的事– POSIX表示在不同的平台上可以有多个时基,但是每个平台都必须至少支持CLOCK_REALTIME时基。在Neutrino下,有 三个时基可供选择:

                        CLOCK_REALTIME重点是这个;
                        CLOCK_SOFTTIME
                        CLOCK_MONOTONIC

         * **/
        timer_create(CLOCK_MONOTONIC, &msg->mEvent, &msg->mTimerId);

        /**
#include <time.h>

            int timer_settime (timer_t timerid,
                        int flags,
                        struct itimerspec *value,
                        struct itimerspec *oldvalue);
         * */
        timer_settime(msg->mTimerId, 0, &itime, NULL);
#endif
    }

#ifdef __QNX__
    void HandlerQueue::onTriggered(union sigval s)
    {
        Message *msgObject = (Message *)s.sival_ptr;
        msgObject->_dispatchQueue.dispatch([&]()
                                            {
            if (msgObject->mTriggeredFunction != nullptr)
            {
                msgObject->mTriggeredFunction();
            } });
        msgObject->mTriggeredFunction();
    }
#endif

一、C++标准实现

如果不想处理平台差异,且对性能要求没有那么高,可以用c++的一些标准实现

定时器的主要数据:
1.一个线程变量,保存定时器线程
2.一个互斥锁,配合条件变量使用
3.一个条件变量,结合互斥锁,可以是线程不执行任务时,睡眠一段时间,在退出调用时,可以唤醒线程完成退出
4.定时执行函数,具体的定时执行业务操作
5.间隔时间,定时器间隔一段时间调用定时执行函数
6.一个退出标识,标志是否退出定时线程循环
7.立即执行标识,标识新建状态的定时线程是否立即执行一次任务,而不需等待一个间隔时间才开始执行第一次任务

 #include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <atomic>
#include <memory>
#include <condition_variable>

using namespace std;


// 定时器类型
/*
   主要数据:
   1.一个线程变量,保存定时器线程
   2.一个互斥锁,配合条件变量使用
   3.一个条件变量,结合互斥锁,可以是线程不执行任务时,睡眠一段时间,在退出调用时,可以唤醒线程完成退出
   4.定时执行函数,具体的定时执行业务操作
   5.间隔时间,定时器间隔一段时间调用定时执行函数
   6.一个退出标识,标志是否退出定时线程循环
   7.立即执行标识,标识新建状态的定时线程是否立即执行一次任务,而不需等待一个间隔时间才开始执行第一次任务
*/
class CTimer
{
public:
    template<class F>
    CTimer(F func) 
        : m_func(func)
    {}

    virtual ~CTimer()
    {}

    // 启动函数
    void Start(unsigned int imsec, bool bimmediately_run = false)
    {
        cout << __FUNCTION__ << endl;
        if (imsec == 0 || imsec == static_cast<unsigned int>(-1)) // 间隔时间为0或默认无效值,直接返回
        {
            return;
        }
        m_bexit.store(false);
        m_imsec = imsec;
        m_bimmediately_run.store(bimmediately_run);
        m_thread = std::thread(std::bind(&CTimer::Run,this));
    }

    // 结束
    void Stop()
    {
        cout << __FUNCTION__ << endl;
        m_bexit.store(true);
        m_cond.notify_all(); // 唤醒线程
        if (m_thread.joinable())
        {
            m_thread.join();
        }
    }

    void SetExit(bool b_exit)
    {
        m_bexit.store(b_exit);
    }

private:
    void Run()
    {
        if (m_bimmediately_run.load()) // 立即执行判断
        {
            if (m_func)
            {
                m_func();
            }
        }

        while (!m_bexit.load())
        {
            {
                // 锁放在花括号内部,减小锁的粒度
                std::unique_lock<std::mutex> locker(m_mutex);

                // 如果是被唤醒的,需要判断先条件确定是不是虚假唤醒
                // wait_for是等待第三个参数满足条件,当不满足时,超时后继续往下执行
                m_cond.wait_for(locker, std::chrono::milliseconds(m_imsec), [this]() { return m_bexit.load(); });
            }

            if (m_bexit.load()) // 再校验下退出标识
            {
                return;
            }

            if (m_func)
            {
                m_func();
            }
        }
    }

private: // 私有数据部分
    std::atomic_bool m_bexit = false;
    std::atomic_bool m_bimmediately_run = false; // 是否立即执行
    unsigned int m_imsec = 1000;    // 间隔时间
    std::function<void()> m_func;    // 执行函数
    std::thread m_thread;
    std::mutex m_mutex;
    std::condition_variable m_cond;
};

int g_index = 0;

// 定时执行函数
void OnTimeFunc()
{
    cout << __FUNCTION__ << ":" << ++g_index << endl;
}

// 测试自己写的定时器
void Test_Timer()
{
    int index = 0;
    std::unique_ptr<CTimer> ptr_timer = std::make_unique<CTimer>(OnTimeFunc);
    if (ptr_timer == nullptr)
    {
        return;
    }
    ptr_timer->Start(1000);
    std::this_thread::sleep_for(std::chrono::seconds(10));

    ptr_timer->Stop(); // 离开作用已记得停止定时器
}


// 程序入口
int main()
{
    Test_Timer();

    cout << "getchar" << endl;
    getchar();
    return 0;
}

Reference:
How to fill in the struct sigevent

QNX系列:三、时钟与定时器


   转载规则


《POSIX 定时器_QNX实现》 pglprome 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
TCP Posix 网络抓包分析 示例 TCP Posix 网络抓包分析 示例
Android QNX内部Virtio net 抓包分析工具:tcpdump + wireshark 背景:负责项目出现Android QNX内部网络丢包问题 解决思路:通过抓包进一步分析root cause,需要通过tcpdump抓两个系
2023-01-05
下一篇 
Android/Java 线程池笔记 Android/Java 线程池笔记
一、为何要使用线程池在Java中,要使用多线程,除了使用new Thread()之外,还可以使用线程池ExecutorService。 // 使用Thread Thread t = new Thread(new Runnable() {
2022-10-08
  目录