Linux下C++定時器類Timer
前段時間在Linux上做了一個協議轉換器,用的是C++。因為需要定時發送報文,所以找了許多Linux下定時器的實現方法,但基本都不太好用,一堆下划線也看得我一個頭兩個大。那怎么辦?自己寫一個。
1、思路
我比較喜歡簡單的、面向對象的東西,所以肯定是要封成一個類,這樣用的時候直接new出來就可以了,很方便。
這個定時器類的原理就是創建一個線程,在這個線程中去sleep,經過指定時間后觸發回調,這樣就達到定時器的效果。實現如下:
2、代碼
.h
#ifndef TIMER_H
#define TIMER_H
#include <stdio.h>
#include <unistd.h>
#include <functional>
#include <thread>
#include <pthread>
#include <iostream>
class Timer {
private:
unsigned seconds = 0;
bool isAlive = false;
public:
Timer(unsigned seconds);
~Timer();
void start(std::function<void ()> handle);
void recycle(std::function<void ()> handle);
void stop();
};
#endif
.cpp
#include "Timer.h"
Timer::Timer(unsigned seconds) {
this->seconds = seconds;
}
Timer::~Timer() {
}
void Timer::start(std::function<void ()> handle) {
if (!this->isAlive) {
this->isAlive = true;
auto timeThread = [=] {
for (int i = 0; i< (this->seconds * 1000); i++) {
if (this->isAlive) {
usleep(1000);
} else {
return;
}
}
if (this->isAlive) {
handle();
}
this->stop();
return;
};
std::thread t(timeThread);
t.detach();
}
}
void Timer::recycle(std::function<void ()> handle) {
if (!this->isAlive) {
this->isAlive = true;
auto timeThread = [=] {
while (this->isAlive) {
for (int i = 0; i < (this->seconds * 1000); i++) {
if (this->isAlive) {
usleep(1000);
} else {
return;
}
}
if (this->isAlive) {
handle();
}
}
};
std::thread t(timeThread);
t.detach();
}
}
void Timer::stop() {
this->isAlive = false;
}
Test.h
#ifndef TIMER_TEST_H
#define TIMER_TEST_H
class TimerTest {
private:
Timer* t;
// 定義一個回調,注意是靜態的
static void onTimeout();
public:
TimerTest();
~TimerTest();
void testStart();
void testRecycle();
void testStop();
};
#endif
Test.cpp
#include "TimerTest.h"
TimerTest::TimerTest() {
this->t = nullptr;
}
TimerTest::~TimerTest() {
delete this->t;
this->t = nullptr;
}
void onTimeout() {
std::cout << "timer run" << std::endl;
}
void TimerTest::testStart() {
if (this->t == nullptr) {
this->t = new Timer(10); // new一個10秒延時的定時器出來
}
this->t->start(onTimeout); // 傳入回調,10秒后執行回調一次,任務結束
}
void TimerTest::testRecycle() {
if (this->t == nullptr) {
this->t = new Timer(10);
}
this->t->recycle(onTimeout); // 傳入回調,循環定時,每10秒執行一次回調
}
void TimerTest::testStop() {
if (this->t == nullptr) {
this->t = new Timer(10);
}
this->t->start(onTimeout);
this->t->stop(); // 停掉前面的start
this->t->recycle(onTimeout);
this->t->stop(); // 停掉前面的recycle
}
3、回調中訪問非靜態成員或方法
因為定時回調是靜態的,所以正常來說在靜態方法中只用訪問到靜態方法或成員。但是又肯定會有需要在回調中調用非靜態成員或方法的情況出現,這個時候可以人為地定義一個靜態指針,使它在所屬類實例化的時候指向對象自身(有些類似於單例模式)。代碼如下:
.h
// 例如我們需要在onTimeout回調中調用Test類中的非靜態成員或方法
// 我們可以在Test類中定義一個指向Test類的靜態指針,並在構造方法中給它賦值this使它指向對象本身
// 這樣我們就可以通過在onTimeout中使用這個靜態指針來訪問Test類中的非靜態成員或方法
#ifndef TIMER_TEST_H
#define TIMER_TEST_H
class TimerTest {
private:
Timer* t;
// 定義一個回調,注意是靜態的
static void onTimeout();
// 現在有一個非靜態成員
std::string hi = "hello";
// 還有一個非靜態方法
void sayHi();
// 那么我們定義一個靜態指針
static TimerTest* self;
public:
TimerTest();
~TimerTest();
void testStart();
void testRecycle();
void testStop();
};
#endif
.cpp
// 我們要在回調中訪問hi和sayHi()
// 初始化靜態指針
TimerTest* TimerTest::self = nullptr;
// 給它this
TimerTest::TimerTest() {
self = this;
}
//回調中訪問
void TimerTest::onTimeout() {
std::cout << self->hi << std::endl; // 訪問非靜態成員
self->sayHi(); // 訪問非靜態方法
}
void TimerTest::sayHi() {
std::cout << this->hi << std::endl;
}
4、說明
優點:使用簡單,可以new出多個定時器
缺點:精度不足,只適用於精度要求不高的場合