使用C++0x与boost编写的异步信号回调计时器类

发布: 2011-04-15 11:45

这个类的接口与QTimer类似,能对现有代码改动极小的情况下取代QTimer

这个类使用linux上的timer_*系统调用实现,只能用于linux平台,但使用boost:signals2实现了类似Qt的信号回调机制。

编写这个类本意是学习一下boost的信号机制,没想到测试效果非常好,达到完成替代QTimer类的功能,在此列出,

[code type="cpp"]
#ifndef NBTIMER_H
#define NBTIMER_H

#include
#include

#include "boost/signals2.hpp"

#define NBSLOT(mf,obj) boost::bind(&mf,obj)
#define NBSLOT1(mf,obj) boost::bind(&mf,obj,_1)
#define NBSLOT2(mf,obj) boost::bind(&mf,obj,_1,_2)
#define NBSLOT3(mf,obj) boost::bind(&mf,obj,_1,_2,_3)
#define NBSLOT4(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4)
#define NBSLOT5(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5)
#define NBSLOT6(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6)
#define NBSLOT7(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7)
#define NBSLOT8(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8)
#define NBSLOT9(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8,_9)

class MyTimer
{
public:
MyTimer();
virtual ~MyTimer();

void start(int msec);
void start();
void stop();
int interval() {return this->m_intval;}
void setInterval(int msec);
bool isSingleShot() { return this->m_is_single_shot; }
bool isActive() {return this->m_started; }

boost::signals2::connection connect(boost::signals2::signal::slot_type slot);

static void singleShot(int msec, boost::signals2::signal::slot_type slot);

public:
static void sig_timeout_handler(int sig, siginfo_t *si, void *uc);
static void print_siginfo(siginfo_t *si);

static void sig_timeout_revoke_back1(siginfo_t *si);
void sig_timeout_revoke_back2();

public: // signals
boost::signals2::signal sig_timeout;

protected:
MyTimer(bool single);
void init_timer_signal();

private:
timer_t m_timer_id;
int m_intval;
struct sigevent m_sev;
bool m_started;
bool m_is_single_shot;
static constexpr timer_t INV_TIMER_ID = NULL;
};

#endif

[/code]

[code type="cpp"]
#include "mytimer.h"

MyTimer::MyTimer()
{
this->m_timer_id = MyTimer::INV_TIMER_ID;
this->m_intval = 0;
this->m_started = false;
this->m_is_single_shot = false;
// printf("====%d\n", this->m_timer_id == MyTimer::INV_TIMER_ID);
}

MyTimer::MyTimer(bool single)
{
new(this)MyTimer();
this->m_is_single_shot = true;
}

MyTimer::~MyTimer()
{
if (this->m_timer_id != MyTimer::INV_TIMER_ID) {
timer_delete(this->m_timer_id);
}
}
// timer_t MyTimer::INV_TIMER_ID = NULL;

void MyTimer::start(int msec)
{
this->m_intval = msec;

if (this->m_timer_id == MyTimer::INV_TIMER_ID) {
this->init_timer_signal();
}

if (!this->m_started) {
this->start();
}
}

void MyTimer::start()
{
int iret;

if (this->m_timer_id == MyTimer::INV_TIMER_ID) {
this->init_timer_signal();
}

if (!this->m_started) {
struct itimerspec itspec, oitspec;
memset(&itspec, 0, sizeof(itspec));
itspec.it_interval.tv_sec = this->m_intval / 1000;
itspec.it_interval.tv_nsec = (this->m_intval % 1000) * 1000000;
// itspec.it_interval.tv_sec = 2;
// itspec.it_interval.tv_nsec = 0;

itspec.it_value.tv_sec = itspec.it_interval.tv_sec;
itspec.it_value.tv_nsec = itspec.it_interval.tv_nsec;

printf("sec: %ld, nsec: %ld\n", itspec.it_interval.tv_sec, itspec.it_interval.tv_nsec);

memset(&oitspec, 0, sizeof(oitspec));

iret = timer_settime(this->m_timer_id, 0, &itspec, NULL);
if (iret == -1) {
perror("set error");
// assert(iret != -1);
}

this->m_started = true;
}
}

void MyTimer::stop()
{
int iret = 0;
if (this->m_timer_id != MyTimer::INV_TIMER_ID) {
struct itimerspec itspec, oitspec;
memset(&itspec, 0, sizeof(struct itimerspec));
memset(&oitspec, 0, sizeof(struct itimerspec));

iret = timer_settime(this->m_timer_id, 0, &itspec, &oitspec);
if (iret == -1) {
perror("set timer stop error");
}
}
}

void MyTimer::setInterval(int msec)
{
this->m_intval = msec;
}

void MyTimer::init_timer_signal()
{
int iret = 0;
sigset_t mask;
struct sigaction sa;

sa.sa_flags = SA_SIGINFO;
// sa.sa_sigaction = sig_timer_handler;
// sa.sa_sigaction = MyTimer::sig_timeout_handler;
sa.sa_sigaction = MyTimer::sig_timeout_handler;
sigemptyset(&sa.sa_mask);
iret = sigaction(SIGRTMIN, &sa, NULL);
assert(iret != -1);

sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN);
// iret = sigprocmask(SIG_SETMASK, &mask, NULL);

this->m_sev.sigev_notify = SIGEV_SIGNAL;
this->m_sev.sigev_signo = SIGRTMIN;
// this->m_sev.sigev_value.sival_ptr = &this->m_timer_id;
this->m_sev.sigev_value.sival_ptr = this;
iret = timer_create(CLOCK_REALTIME, &this->m_sev, &this->m_timer_id);
printf("timer:%p\n", this->m_timer_id);
assert(iret != -1);

}

// #include "boost/lambda/lambda.hpp"
// #include "boost/lambda/bind.hpp"
// #include "boost/lambda/if.hpp"

struct abcde {
void operator()(int a) {
printf("ahaha: %d\n", a);
}
};

boost::signals2::connection MyTimer::connect(boost::signals2::signal::slot_type slot)
{
boost::signals2::connection conn;

conn = this->sig_timeout.connect(slot);

return conn;

boost::function onClick;

// ok
onClick = slot;

// ok
onClick = {
};
onClick();

// ok
onClick = slot;

boost::function onChange;

// ok
onChange = abcde();

// onChange = (std::cout<< boost::lambda::_1 <<" "< // (std::cout<< boost::lambda::_1 << boost::lambda::_3 << boost::lambda::_2)("adf","fd","dfd");

[](int x) -> int {
return x + 6;
};

int x = 5;
char *y = NULL;
std::string z;

[=](int x) -> int {
if (y == NULL) {
}
return x + 6;
};

[&](int x) -> int {
if (y == NULL) {
}
return x + 6;
};

[&y,&z](int x) -> int {
if (y == NULL) {
}
return x + 6;
};

auto my_lambda_func = [&](int x) { /*...*/ };
auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });
my_lambda_func(5);
(*my_onheap_lambda_func)(6);

using namespace std;
vector v = {50, -10, 20, -30};

// gcc version problem, go to gcc 4.6.0 now
std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a)
struct BasicStruct {
int x;
double y;
};

struct AltStruct {
AltStruct(int x, double y) : x_{x}, y_{y} {}

private:
int x_;
double y_;
};

BasicStruct var1{5, 3.2};
AltStruct var2{2, 4.3};

}

// static
void MyTimer::singleShot(int msec, boost::signals2::signal::slot_type slot)
{
MyTimer *t = new MyTimer(true);
t->setInterval(msec);
t->connect(slot);
t->start();
}

// static
void MyTimer::sig_timeout_handler(int sig, siginfo_t *si, void *uc)
{
/* Note: calling printf() from a signal handler is not
strictly correct, since printf() is not async-signal-safe;
see signal(7) */

printf("Caught signal %d\n", sig);
[] (siginfo_t*si) {
// MyTimer::print_siginfo(si);
MyTimer::print_siginfo(si);
} (si);


MyTimer::sig_timeout_revoke_back1(si);
// signal(sig, SIG_IGN);
}

// static
void MyTimer::print_siginfo(siginfo_t *si)
{
timer_t *tidp;
int oret;

// tidp = (timer_t*)si->si_value.sival_ptr;

// printf(" sival_ptr = %p; ", si->si_value.sival_ptr);
// printf(" *sival_ptr = 0x%lx\n", (long) *tidp);

// oret = timer_getoverrun(*tidp);
// if (oret == -1) {
// perror("timer_getoverrun");
// }
// else
// printf(" overrun count = %d\n", oret);


}

// static
void MyTimer::sig_timeout_revoke_back1(siginfo_t *si)
{
MyTimer *t = NULL;

t = (MyTimer*)si->si_value.sival_ptr;
t->sig_timeout_revoke_back2();
}

void MyTimer::sig_timeout_revoke_back2()
{
printf("sig timeout arrived:\n");
this->sig_timeout();
if (this->m_is_single_shot) {
this->stop();
delete this;
}
}

[/code]


原文: http://qtchina.tk/?q=node/570

Powered by zexport