一、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