Linux下C++定時器類Timer


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出多個定時器

缺點:精度不足,只適用於精度要求不高的場合


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM