0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

定時器設(shè)計實現(xiàn)

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-08 16:50 ? 次閱讀

由于目前C++標(biāo)準中沒有現(xiàn)成的定時器,本設(shè)計使用C++11相關(guān)語法并進行封裝。

本定時器包含一個TimerManager類用于創(chuàng)建定時器和進行定時任務(wù)管理,TimerManager會創(chuàng)建兩個線程(mTimerTickThread、mTimerCallbackThread)分別用于時間處理和函數(shù)回調(diào)。

可以使用TimerManager的create方法創(chuàng)建多個定時器,每次創(chuàng)建的定時器ID會累加,并返回ITimer類型的共享指針。其中ITimer類中定義了start和stop方法,用于啟動或停止當(dāng)前定時器。

TimerManager還有一個內(nèi)部類TimerMessageQueue用于實現(xiàn)定時器消息的插入、刪除與定時控制。

關(guān)鍵類型及接口介紹

TimerMessage類型作為通信的元素類型

using TimerCallback = std::function;

struct TimerMessage {
const int id; // time id.
const long long timeout; // time out value.
const TimerCallback callback; // timeout callback function.
const TimerType type; // 0:once, 1:periodic.
long long when; // time out occure time.
bool valid; // set true when timeout and pop from message queue.

TimerMessage()
: id(0), timeout(0), callback(nullptr), type(ONCE_TIMER), when(0), valid(false)
{}

TimerMessage(const int &id, const long long &timeout, const TimerCallback &callback,
const TimerType &type = ONCE_TIMER)
: id(id), timeout(timeout), callback(callback), type(type), when(0), valid(false)
{}
};()>

id、timeout、callback、type伴隨著timer的生命周期,一旦創(chuàng)建不可修改。
when、valid為輔助信息,在消息流轉(zhuǎn)過程中適時變化。

TimerManager的create方法

std::shared_ptr create(const long long &timeoutMillis, const TimerCallback &callback,
const TimerType &type = TIMERTYPE_ONCE);

用于創(chuàng)建定時器,有三個參數(shù),分別是定時時長(單位毫秒),超時callback用于定時器到期的回調(diào)函數(shù),定時器類型(單次還是循環(huán)定時器)。

定時器類的start、stop方法

bool start(void);
void stop(void);

start時會向TimerMessageQueue中插入消息,該消息包括定時器id、超時時間timeout、回調(diào)函數(shù)callback、定時器類型type、到期時間when,插入時按when進行排序(二分法、復(fù)雜度為log2N);

stop時會依據(jù)id從TimerMessageQueue中刪除消息,并將valid設(shè)置為false,防止繼續(xù)callback;

在重復(fù)start時會先stop原來的定時器再重新start,到期時間以最后一次start的時間為準。

核心邏輯介紹

TimerMessageQueue的插入與刪除實現(xiàn),確保消息能高效的按序插入對應(yīng)位置。

bool enqueueMessage(const TimerMessageRefPtr &message, const long long &when)
{
do {
std::lock_guard lg(mMuxLock);
mMapIdWhens[message->id].push_back(when);
LOGD("add message id:%d, when:%lld", message->id, when);
message->when = when;
mMessages.insert(
std::upper_bound(mMessages.begin(), mMessages.end(), when,
[](const long long &when, const TimerMessageRefPtr &m) {
return (when < m->when);
}),
message);
} while (0);

mCond.notify_one();
std::this_thread::yield();
return true;
}

void removeMessages(const int &id)
{
std::lock_guard lg(mMuxLock);
auto it = mMapIdWhens.find(id);
if (it == mMapIdWhens.end()) {
return;
}
for (auto const &when : it->second) {
LOGD("del message id:%d, when:%lld", id, when);
mMessages.erase(
std::remove_if(
std::lower_bound(mMessages.begin(), mMessages.end(), when,
[](const TimerMessageRefPtr &m, const long long &when) {
return (m->when < when);
}),
std::upper_bound(mMessages.begin(), mMessages.end(), when,
[](const long long &when, const TimerMessageRefPtr &m) {
return (when < m->when);
}),
[&id](const TimerMessageRefPtr &m) { return ((id == m->id)); }),
mMessages.end());
}
mMapIdWhens.erase(id);
}

bool hasMessages(const int &id) const
{
std::lock_guard lg(mMuxLock);
bool ret = (mMapIdWhens.end() != mMapIdWhens.find(id));
LOGV("has message id:%d %s", id, ret ? "yes" : "no");
return ret;
}

std::lower_bound和std::upper_bound用于在有序的容器中快速查找可插入位置(不小于目標(biāo)值和不大于目標(biāo)值的位置)迭代器。

取出定時器到期消息

mTimerTickThread用于從mTimerTickQueue中取出到期的定時器消息。

如果沒有到期消息則會休眠等待,等待的時間是最近要到期的時間與當(dāng)前時間差,并且可以隨時被打斷(當(dāng)有新的消息插入時會打斷);

由于消息插入時是按到期時間排序插入的,所以每次取出的都是最近要到期的那一條定時消息。

inline void waitForItems(void)
{
std::unique_lock ul(mMuxLock);
mCond.wait(ul, [this]() { return !mMessages.empty(); });
if (0 == mMessages.front()->when) {
return;
}

long long waitingTimeMicros = 0;
while (!mMessages.empty()
&& (waitingTimeMicros = mMessages.front()->when - steadyTimeMicros()) > 0) {
// next message is not ready, set a timeout to wake up when it is ready.
mCond.wait_for(ul, std::chrono::microseconds(waitingTimeMicros));
}
}

inline TimerMessageRefPtr next(void)
{
while (true) {
waitForItems();
do {
std::lock_guard lg(mMuxLock); // minimise the lock scope.
if (!mMessages.empty()
&& (steadyTimeMicros() >= mMessages.front()->when)) { // time is up.
TimerMessageRefPtr msg = std::move(mMessages.front());
mMessages.pop_front();
msg->valid = true;

// remove message by id and when from map.
auto &whens = mMapIdWhens[msg->id];
whens.erase(std::remove_if(whens.begin(), whens.end(),
[&msg](const long long &when) {
return when == msg->when;
}),
whens.end());
if (whens.empty()) {
mMapIdWhens.erase(msg->id);
}

LOGD("pop message id:%d, when:%lld", msg->id, msg->when);
return msg;
}
} while (0);
}
}

處理定時器到期消息

mTimerTickThread從mTimerTickQueue中取出到期的定時器消息后,再插入mCallbackQueue中,供mTimerCallbackThread線程調(diào)用回調(diào)函數(shù)完成定時器超時回調(diào)通知。

如果是循環(huán)定時器,則將定時消息的到期時間when加上超時時間timeout后重新插入mTimerTickQueue中,繼續(xù)進行對應(yīng)消息的流轉(zhuǎn)。

do {
auto message = mTimerTickQueue->next();
if (!message) {
continue;
}
if (!message->callback) {
// No callback is a magic identifier for the quit message.
break;
}
do {
std::unique_lock ul(mMutexLock);
if (!message->valid) {
break;
}
if (PERIODIC_TIMER == message->type) {
(void)mTimerTickQueue->enqueueMessage(message,
message->when + message->timeout);
}

(void)mCallbackQueue->push_back(message);
ul.unlock();

mCond.notify_one();
std::this_thread::yield();
} while (0);
} while (mMainThreadAlive);

回調(diào)定時器回調(diào)函數(shù)

mTimerCallbackThread線程從mCallbackQueue中取出消息并調(diào)用回調(diào)函數(shù)完成定時器超時回調(diào)通知。

TimerMessageRefPtr message = nullptr;
do {
std::unique_lock ul(mMutexLock);
mCond.wait(ul, [this]() { return !mCallbackQueue->empty(); });

message = mCallbackQueue->front();
mCallbackQueue->pop_front();
if (!message) {
continue;
}
if (!message->callback) {
// No callback is a magic identifier for the quit message.
break;
}
if (!message->valid) {
continue;
}

// handler dispatch message.
LOGV("callback message id:%d, when:%lld", message->id, message->when);
message->callback();
ul.unlock();

std::this_thread::yield();
} while (mMainThreadAlive);

使用步驟舉例

1.create timer manager instance

auto timerMgr = mdtimer::TimerManager::getInstance();

2.create timer instance

auto timer1 = timerMgr->create(50, std::bind(timeoutCallback, "once timer1, 50ms"));
auto timer2 = timerMgr->create(100, std::bind(timeoutCallback, "periodic timer2, 100ms"),
mdtimer::PERIODIC_TIMER);

3.start timer

(void)timer1->start();
(void)timer2->start();

4.stop timer

timer1->stop();
timer2->stop();

參考代碼

定時器實現(xiàn)

/*
* Copyright (C) 2023 . All rights reserved.
*
* File name : MDTimer.hpp
* Author : longbin
* Created date: 2020-05-07 21:54:42
* Description : message driven timer
*
*/
#ifndef __MDTIMER_HPP__
#define __MDTIMER_HPP__

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#ifdef LOG_TAG
# undef LOG_TAG
#endif // LOG_TAG
#define LOG_TAG "MDTimer"
#include "logging.hpp"

// usage:
// 1. create timer manager instance;
// auto timerMgr = mdtimer::TimerManager::getInstance();
// 2. create timer instance;
// auto timer1 = timerMgr -> create(50, std::bind(timeoutCallback, "once timer1, 50ms"));
// auto timer2 = timerMgr -> create(100, std::bind(timeoutCallback, "periodic timer2, 100ms"),
// mdtimer::PERIODIC_TIMER);
// 3. start timer;
// (void)timer1->start();
// (void)timer2->start();
// 4. stop timer;
// timer1->stop();
// timer2->stop();

namespace mdtimer
{

using TimerType = enum TimerType { ONCE_TIMER = 0, PERIODIC_TIMER = 1 };

class ITimer
{
public:
virtual ~ITimer() = default;

virtual bool start(void) = 0;
virtual void stop(void) = 0;
}; // class ITimer

class TimerManager : public std::enable_shared_from_this
{
private:
using TimerCallback = std::function;
class TimerMessage;
using TimerMessageRefPtr = std::shared_ptr;
using TimerMessageRefPtrList = std::deque;
using TimerManagerRefPtr = std::shared_ptr;

struct TimerMessage {
const int id; // time id.
const long long timeout; // time out value.
const TimerCallback callback; // timeout callback function.
const TimerType type; // 0:once, 1:periodic.
long long when; // time out occure time.
bool valid; // set true when timeout and pop from message queue.

TimerMessage()
: id(0), timeout(0), callback(nullptr), type(ONCE_TIMER), when(0), valid(false)
{}

TimerMessage(const int &id, const long long &timeout, const TimerCallback &callback,
const TimerType &type = ONCE_TIMER)
: id(id), timeout(timeout), callback(callback), type(type), when(0), valid(false)
{}
};

class TimerMessageQueue
{
private:
constexpr static bool mShowMessages = false;

TimerMessageRefPtrList mMessages{};
std::map> mMapIdWhens;
mutable std::mutex mMuxLock;
std::condition_variable mCond;

private:
TimerMessageQueue(const TimerMessageQueue &) = delete;
TimerMessageQueue &operator=(const TimerMessageQueue &) = delete;

inline void showMessages()
{
std::string queue{};
std::for_each(mMessages.begin(), mMessages.end(),
[&queue](const TimerMessageRefPtr &m) {
queue += std::to_string(m->id) + ":" + std::to_string(m->when) + " ";
});
LOGD("show messages (size:%zu) %s", mMessages.size(), queue.c_str());
}

inline void waitForItems(void)
{
std::unique_lock ul(mMuxLock);
mCond.wait(ul, [this]() { return !mMessages.empty(); });
if (0 == mMessages.front()->when) {
return;
}

long long waitingTimeMicros = 0;
while (!mMessages.empty()
&& (waitingTimeMicros = mMessages.front()->when - steadyTimeMicros()) > 0) {
// next message is not ready, set a timeout to wake up when it is ready.
mCond.wait_for(ul, std::chrono::microseconds(waitingTimeMicros));
}
}

public:
TimerMessageQueue() = default;
virtual ~TimerMessageQueue() = default;

TimerMessageRefPtr next(void)
{
while (true) {
waitForItems();
do {
std::lock_guard lg(mMuxLock); // minimise the lock scope.
if (!mMessages.empty()
&& (steadyTimeMicros() >= mMessages.front()->when)) { // time is up.
TimerMessageRefPtr msg = std::move(mMessages.front());
mMessages.pop_front();
msg->valid = true;

// remove message by id and when from map.
auto &whens = mMapIdWhens[msg->id];
whens.erase(std::remove_if(whens.begin(), whens.end(),
[&msg](const long long &when) {
return when == msg->when;
}),
whens.end());
if (whens.empty()) {
mMapIdWhens.erase(msg->id);
}

LOGD("pop message id:%d, when:%lld", msg->id, msg->when);
return msg;
}
} while (0);
}
}

bool enqueueMessage(const TimerMessageRefPtr &message, const long long &when)
{
do {
std::lock_guard lg(mMuxLock);
mMapIdWhens[message->id].push_back(when);
LOGD("add message id:%d, when:%lld", message->id, when);
message->when = when;
mMessages.insert(
std::upper_bound(mMessages.begin(), mMessages.end(), when,
[](const long long &when, const TimerMessageRefPtr &m) {
return (when < m->when);
}),
message);

if (mShowMessages) {
showMessages();
}
} while (0);

mCond.notify_one();
std::this_thread::yield();
return true;
}

void removeMessages(const int &id)
{
std::lock_guard lg(mMuxLock);
auto it = mMapIdWhens.find(id);
if (it == mMapIdWhens.end()) {
return;
}
for (auto const &when : it->second) {
LOGD("del message id:%d, when:%lld", id, when);
mMessages.erase(
std::remove_if(
std::lower_bound(mMessages.begin(), mMessages.end(), when,
[](const TimerMessageRefPtr &m, const long long &when) {
return (m->when < when);
}),
std::upper_bound(mMessages.begin(), mMessages.end(), when,
[](const long long &when, const TimerMessageRefPtr &m) {
return (when < m->when);
}),
[&id](const TimerMessageRefPtr &m) { return ((id == m->id)); }),
mMessages.end());
}
mMapIdWhens.erase(id);

if (mShowMessages) {
showMessages();
}
}

bool hasMessages(const int &id) const
{
std::lock_guard lg(mMuxLock);
bool ret = (mMapIdWhens.end() != mMapIdWhens.find(id));
LOGV("has message id:%d %s", id, ret ? "yes" : "no");
return ret;
// return mMessages.end()
// != std::find_if(mMessages.begin(), mMessages.end(),
// [&id](const TimerMessageRefPtr &m) { return ((id == m->id));
// });
}
}; // class TimerMessageQueue

class TimerImpl : public ITimer
{
friend class TimerManager; // to access its private start/stop
private:
TimerManagerRefPtr mTimerManager = nullptr;
TimerMessageRefPtr mTimerMessage = nullptr;

public:
explicit TimerImpl(const TimerManagerRefPtr &manager, const int &id,
const long long &timeoutMillis, const TimerCallback &callback,
const TimerType &type)
{
LOGI("create timer id:%d, timeout:%lldms, type:%d", id, timeoutMillis, type);
mTimerManager = manager;
mTimerMessage =
std::make_shared(id, timeoutMillis * 1000, callback, type);
}

virtual ~TimerImpl()
{
LOGI("destroy timer id:%d", mTimerMessage->id);
this->stop(); // if destroy timer manager before timer the stop will be blocked.
}

virtual bool start(void) override
{
mTimerMessage->when = mTimerMessage->timeout + steadyTimeMicros();
return mTimerManager ? mTimerManager->start(mTimerMessage) : false;
}

virtual void stop(void) override
{
if (mTimerManager) {
mTimerManager->stop(mTimerMessage);
}
}
}; // class TimerImpl

public:
virtual ~TimerManager()
{
LOGD("~TimerManager");
mMainThreadAlive = false;

(void)mCallbackQueue->push_back(std::make_shared());
mCond.notify_all();

(void)mTimerTickQueue->enqueueMessage(std::make_shared(), 0);
(void)mTimerTickQueue->enqueueMessage(std::make_shared(), -1);

if (mTimerTickThread.joinable()) {
mTimerTickThread.join();
}
if (mTimerCallbackThread.joinable()) {
mTimerCallbackThread.join();
}
}

static std::shared_ptr getInstance(void)
{
static std::shared_ptr instance =
std::shared_ptr(new TimerManager());
return instance;
}

std::shared_ptr create(const long long &timeoutMillis, const TimerCallback &callback,
const TimerType &type = ONCE_TIMER)
{
int id = mTimerId.fetch_add(1);
return std::shared_ptr(
new TimerImpl(shared_from_this(), id, timeoutMillis, callback, type));
}

static long long steadyTimeMicros(void)
{
auto now = std::chrono::time_point_cast(
std::chrono::steady_clock::now());
std::chrono::microseconds span =
std::chrono::duration_cast(now.time_since_epoch());
return span.count();
}

private:
TimerManager(const TimerManager &) = delete;
TimerManager &operator=(const TimerManager &) = delete;

TimerManager() : mMainThreadAlive(true)
{
mTimerTickThread = std::thread([this]() {
do {
auto message = mTimerTickQueue->next();
if (!message) {
continue;
}
if (!message->callback) {
// No callback is a magic identifier for the quit message.
break;
}
do {
std::unique_lock ul(mMutexLock);
if (!message->valid) {
break;
}
if (PERIODIC_TIMER == message->type) {
(void)mTimerTickQueue->enqueueMessage(message,
message->when + message->timeout);
}

(void)mCallbackQueue->push_back(message);
ul.unlock();

mCond.notify_one();
std::this_thread::yield();
} while (0);
} while (mMainThreadAlive);

LOGI("TimerTickThread exit.");
});

mTimerCallbackThread = std::thread([this]() {
TimerMessageRefPtr message = nullptr;
do {
std::unique_lock ul(mMutexLock);
mCond.wait(ul, [this]() { return !mCallbackQueue->empty(); });

message = mCallbackQueue->front();
mCallbackQueue->pop_front();
if (!message) {
continue;
}
if (!message->callback) {
// No callback is a magic identifier for the quit message.
break;
}
if (!message->valid) {
continue;
}

// handler dispatch message.
LOGV("callback message id:%d, when:%lld", message->id, message->when);
message->callback();
ul.unlock();

std::this_thread::yield();
} while (mMainThreadAlive);

LOGI("TimerCallbackThread exit.");
});
}

inline bool start(const TimerMessageRefPtr &message)
{
std::lock_guard lg(mMutexLock);
LOGI("start timer id:%d, timeout:%lldms", message->id, message->timeout / 1000);

// stop the exist timer then start.
if (mTimerTickQueue->hasMessages(message->id)) {
mTimerTickQueue->removeMessages(message->id);
}
mCallbackQueue->erase(std::remove_if(mCallbackQueue->begin(), mCallbackQueue->end(),
[&message](const TimerMessageRefPtr &m) {
return ((message->id == m->id));
}),
mCallbackQueue->end());
message->valid = false;

return mTimerTickQueue->enqueueMessage(message, message->when);
}

inline void stop(const TimerMessageRefPtr &message)
{
std::lock_guard lg(mMutexLock);
LOGI("stop timer id:%d", message->id);

if (mTimerTickQueue->hasMessages(message->id)) {
mTimerTickQueue->removeMessages(message->id);
}
mCallbackQueue->erase(std::remove_if(mCallbackQueue->begin(), mCallbackQueue->end(),
[&message](const TimerMessageRefPtr &m) {
return ((message->id == m->id));
}),
mCallbackQueue->end());
message->valid = false;
}

private:
std::atomic mTimerId{1};
std::shared_ptr mTimerTickQueue = std::make_shared();
std::shared_ptr> mCallbackQueue =
std::make_shared>();
std::atomic mMainThreadAlive{true};
std::thread mTimerTickThread;
std::thread mTimerCallbackThread;
mutable std::mutex mMutexLock;
std::condition_variable mCond;
}; // class TimerManager

}; // namespace mdtimer
#endif //__MDTIMER_HPP__,>()>

定時器使用例子

/*****************************************
* Copyright (C) 2020 * Ltd. All rights reserved.
* File name : mdtimertest.cpp
* Created date: 2020-05-07 00:35:00
*******************************************/

#include
#include
#include

#include
#include
// #include "callstack.h"

#include "MDTimer.hpp"

#ifdef LOG_TAG
# undef LOG_TAG
#endif // LOG_TAG
#define LOG_TAG "MDTimerTest"
#include "logging.hpp"

static void timeoutCallback(const std::string &info)
{
LOGI("timeoutCallback: %s", info.c_str());
}

void signal_SEGV_handler(int signo)
{
LOGE("caught signal: %d", signo);
// callstack_dump("CALLSTACK");
/* reset signal handle to default */
(void)signal(signo, SIG_DFL);
/* will receive SIGSEGV again and exit app */
}

int main()
{
(void)signal(SIGSEGV, signal_SEGV_handler);

auto timerMgr = mdtimer::TimerManager::getInstance();
if (timerMgr == nullptr) {
LOGE("ERROR: create timer failed.");
return -1;
}

// std::this_thread::sleep_for(std::chrono::seconds(3));
auto timer1 = timerMgr->create(50, std::bind(timeoutCallback, "once timer1, 50ms"));
(void)timer1->start();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
timer1->stop();

//周期性執(zhí)行定時任務(wù)
auto timer2 = timerMgr->create(100, std::bind(timeoutCallback, "periodic timer2, 100ms"),
mdtimer::PERIODIC_TIMER);
(void)timer2->start();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
timer2->stop();

//周期性執(zhí)行定時任務(wù)
auto timer3 = timerMgr->create(1000, std::bind(timeoutCallback, "periodic timer3, 1000ms"),
mdtimer::PERIODIC_TIMER);
(void)timer3->start();
std::this_thread::sleep_for(std::chrono::milliseconds(5000));

(void)timer1->start();
(void)timer2->start();
(void)timer3->start();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
timer1->stop();
timer2->stop();
timer3->stop();

#if 1
auto timer4 = timerMgr->create(20, std::bind(timeoutCallback, "periodic timer4, 20ms"),
mdtimer::PERIODIC_TIMER);
(void)timer4->start();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
timer4->stop();
#endif
#if 0
auto timer5 = timerMgr->create(10, std::bind(timeoutCallback, "periodic timer5, 10ms"),
mdtimer::PERIODIC_TIMER);
for (auto i = 0; i < 2000; i++) {
(void)timer5->start();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
timer5->stop();
// std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
#endif

LOGI("the end.");
return 0;
}

運行l(wèi)og

2023-06-12 14:10:13.374461 13360 13360 I MDTimer:191 create TimerImpl id:1, timeout:50, type:0
2023-06-12 14:10:13.374531 13360 13360 I MDTimer:329 start id:1, timeout:50ms
2023-06-12 14:10:13.425528 13360 13362 I MDTimerTest:25 timeoutCallback: timer1: once, 50ms
2023-06-12 14:10:13.475776 13360 13360 I MDTimer:344 stop id:1
2023-06-12 14:10:13.475813 13360 13360 I MDTimer:191 create TimerImpl id:2, timeout:100, type:1
2023-06-12 14:10:13.475817 13360 13360 I MDTimer:329 start id:2, timeout:100ms
2023-06-12 14:10:13.577174 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:13.687436 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:13.778635 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:13.876929 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:13.976795 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:14.076345 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:14.177249 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:14.276597 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:14.376828 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:14.476367 13360 13360 I MDTimer:344 stop id:2
2023-06-12 14:10:14.476445 13360 13360 I MDTimer:191 create TimerImpl id:3, timeout:1000, type:1
2023-06-12 14:10:14.476460 13360 13360 I MDTimer:329 start id:3, timeout:1000ms
2023-06-12 14:10:15.477362 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:16.477212 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:17.477276 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:18.477688 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:19.476631 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:19.476740 13360 13360 I MDTimer:329 start id:1, timeout:50ms
2023-06-12 14:10:19.476775 13360 13360 I MDTimer:329 start id:2, timeout:100ms
2023-06-12 14:10:19.476784 13360 13360 I MDTimer:329 start id:3, timeout:1000ms
2023-06-12 14:10:19.527071 13360 13362 I MDTimerTest:25 timeoutCallback: timer1: once, 50ms
2023-06-12 14:10:19.576829 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:19.676966 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:19.777616 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:19.877071 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:19.978404 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.076912 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.177797 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.277207 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.377493 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.477006 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.477045 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:20.577124 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.677249 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.777554 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.878031 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:20.977304 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.076999 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.177763 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.277001 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.377242 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.477678 13360 13362 I MDTimerTest:25 timeoutCallback: timer2: periodic, 100ms
2023-06-12 14:10:21.477737 13360 13362 I MDTimerTest:25 timeoutCallback: timer3: periodic, 1000ms
2023-06-12 14:10:21.479624 13360 13360 I MDTimer:344 stop id:1
2023-06-12 14:10:21.479692 13360 13360 I MDTimer:344 stop id:2
2023-06-12 14:10:21.479707 13360 13360 I MDTimer:344 stop id:3
2023-06-12 14:10:21.479718 13360 13360 I MDTimer:191 create TimerImpl id:4, timeout:20, type:1
2023-06-12 14:10:21.479730 13360 13360 I MDTimer:329 start id:4, timeout:20ms
2023-06-12 14:10:21.499973 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.520535 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.540938 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.560465 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.584846 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.600391 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.619945 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.640485 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.661126 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.680551 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.700040 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.720451 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.741117 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.761350 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.780723 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.803386 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.820695 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.840791 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.860119 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.880511 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.900001 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.920576 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.941140 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.960555 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:21.980128 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.000512 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.019996 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.040414 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.060041 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.080564 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.099851 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.122287 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.140901 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.160394 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.179968 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.200225 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.220663 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.239965 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.260511 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.280020 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.305578 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.320103 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.340671 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.360015 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.380570 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.401000 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.420479 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.439866 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.460528 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.479953 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.500648 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.520394 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.540747 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.561312 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.580095 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.600382 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.620899 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.640418 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.659902 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.680163 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.703046 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.720542 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.740724 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.760168 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.780537 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.800054 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.820631 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.840785 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.860125 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.881097 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.900537 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.920620 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.941611 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.960467 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.979897 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:22.999982 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.020105 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.040916 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.060492 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.079993 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.100434 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.120644 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.140971 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.160481 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.181060 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.201456 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.222556 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.239880 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.260501 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.280484 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.299980 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.321099 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.340601 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.360090 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.380639 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.400425 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.422625 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.440473 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.460980 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.480272 13360 13362 I MDTimerTest:25 timeoutCallback: timer4: periodic, 20ms
2023-06-12 14:10:23.481266 13360 13360 I MDTimer:344 stop id:4
2023-06-12 14:10:23.481313 13360 13360 I MDTimerTest:88 the end.
2023-06-12 14:10:23.481323 13360 13360 I MDTimer:203 destroy TimerImpl id:4
2023-06-12 14:10:23.481329 13360 13360 I MDTimer:344 stop id:4
2023-06-12 14:10:23.481336 13360 13360 I MDTimer:203 destroy TimerImpl id:3
2023-06-12 14:10:23.481341 13360 13360 I MDTimer:344 stop id:3
2023-06-12 14:10:23.481348 13360 13360 I MDTimer:203 destroy TimerImpl id:2
2023-06-12 14:10:23.481353 13360 13360 I MDTimer:344 stop id:2
2023-06-12 14:10:23.481360 13360 13360 I MDTimer:203 destroy TimerImpl id:1
2023-06-12 14:10:23.481365 13360 13360 I MDTimer:344 stop id:1
2023-06-12 14:10:23.481371 13360 13360 I MDTimer:291 ~TimerManager.
2023-06-12 14:10:23.481467 13360 13361 I MDTimer:256 TimerTickThread exit.
2023-06-12 14:10:23.481629 13360 13362 I MDTimer:285 TimerCallbackThread exit.

后續(xù)思考

  1. 本定時器設(shè)計簡潔高效,應(yīng)用方便,滿足絕大多數(shù)場景的使用;
  2. 當(dāng)需要創(chuàng)建或管理大量定時器時,由于定時器start時插入消息時間復(fù)雜度為O(log2N),但stop時直接刪除消息時間復(fù)雜度為O(N),因此引入了輔助的map用于解決該問題,使時間復(fù)雜度變?yōu)閘og2N;也可以使用時間輪定時器來優(yōu)化,但處理邏輯會比較復(fù)雜。
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8598

    瀏覽量

    151163
  • 定時器
    +關(guān)注

    關(guān)注

    23

    文章

    3248

    瀏覽量

    114816
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62622
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2108

    瀏覽量

    73651
收藏 人收藏

    評論

    相關(guān)推薦

    什么是軟件定時器? 軟件定時器實現(xiàn)原理是什么?

    什么是軟件定時器?軟件定時器實現(xiàn)原理是什么?
    發(fā)表于 11-24 06:43

    如何使用lvgl定時器實現(xiàn)動畫效果

    在LVGL中,如何使用lvgl定時器實現(xiàn)動畫效果
    發(fā)表于 12-15 15:23

    PHP定時器實現(xiàn)每隔幾秒運行一次方法詳解

    本文為大家介紹PHP定時器實現(xiàn)每隔幾秒運行一次方法詳解。
    發(fā)表于 01-28 09:35 ?1.6w次閱讀
    PHP<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>每隔幾秒運行一次方法詳解

    如何基于51單片機利用定時器實現(xiàn)PWM的方法詳細概述

    51單片機是可以輸出PWM的,比較的麻煩。此時需要用到內(nèi)部定時器實現(xiàn),可用兩個定時器實現(xiàn),也可以用一個定時器
    的頭像 發(fā)表于 06-12 20:01 ?3.3w次閱讀

    基于STM32定時器實現(xiàn)毫秒延時函數(shù)

    STM32定時器包含基本定時器、通用定時器和高級定時器,其中TIM6和TIM7是STM32當(dāng)中的基本定時器,作為初學(xué)者,先從最基本的學(xué)起最容
    發(fā)表于 10-12 15:54 ?2.5w次閱讀
    基于STM32<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>毫秒延時函數(shù)

    如何使用51單片機定時器實現(xiàn)LED閃爍程序和資料免費下載

    本文檔的主要內(nèi)容詳細介紹的是如何使用51單片機定時器實現(xiàn)LED閃爍程序和資料免費下載。
    發(fā)表于 07-08 17:13 ?3次下載
    如何使用51單片機<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>LED閃爍程序和資料免費下載

    使用51單片機的定時器實現(xiàn)LED閃爍的程序免費下載

    本文檔的主要內(nèi)容詳細介紹的是使用51單片機的定時器實現(xiàn)LED閃爍的程序免費下載。
    發(fā)表于 08-22 17:30 ?7次下載
    使用51單片機的<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>LED閃爍的程序免費下載

    什么是SysTick定時器?實現(xiàn)STM32時鐘系統(tǒng)的詳細資料說明

    什么是SysTick定時器?實現(xiàn)STM32時鐘系統(tǒng)的詳細資料說明主要內(nèi)容包括了:Systick原理和配置方法,ALIENTEK 延時函數(shù)delay講解
    發(fā)表于 01-02 08:00 ?3次下載
    什么是SysTick<b class='flag-5'>定時器</b>?<b class='flag-5'>實現(xiàn)</b>STM32時鐘系統(tǒng)的詳細資料說明

    使用定時器實現(xiàn)閃爍電路的資料免費下載

    本文檔的主要內(nèi)容詳細介紹的是使用定時器實現(xiàn)閃爍電路的資料免費下載
    發(fā)表于 07-07 08:00 ?0次下載
    使用<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>閃爍電路的資料免費下載

    使用555定時器實現(xiàn)延時關(guān)燈的PCB原理圖免費下載

    本文檔的主要內(nèi)容詳細介紹的是使用555定時器實現(xiàn)延時關(guān)燈的PCB原理圖免費下載。
    發(fā)表于 09-22 16:25 ?49次下載
    使用555<b class='flag-5'>定時器</b><b class='flag-5'>實現(xiàn)</b>延時關(guān)燈的PCB原理圖免費下載

    labview定時器實現(xiàn)實例分享

    labview定時器實現(xiàn)實例分享
    發(fā)表于 01-11 09:35 ?26次下載

    利用定時器實現(xiàn)的走馬燈程序

    AWPLC 是 ZLG 自主研發(fā)的 PLC 系統(tǒng)(兼容 IEC61131-3),本文用一個用定時器實現(xiàn)的走馬燈程序,來演示如何用 AWTK 和 AWPLC 快速開發(fā)嵌入式應(yīng)用程序。
    的頭像 發(fā)表于 10-19 11:56 ?1648次閱讀

    使用555定時器實現(xiàn)延時關(guān)燈

    使用555定時器實現(xiàn)延時關(guān)燈
    發(fā)表于 11-21 14:54 ?11次下載

    555定時器如何實現(xiàn)多諧振蕩?

    555定時器如何實現(xiàn)多諧振蕩 555定時器作為一種常見的時序集成電路,在電子工程的應(yīng)用中扮演著非常重要的角色。它具有廣泛的應(yīng)用領(lǐng)域,例如頻率分頻、計時、方波發(fā)生和多諧振蕩等。這篇文章
    的頭像 發(fā)表于 09-02 16:19 ?2678次閱讀

    STM32如何使用定時器實現(xiàn)微秒(us)級延時?

    STM32如何使用定時器實現(xiàn)微秒(us)級延時? 在STM32微控制中,可以使用定時器實現(xiàn)微秒級延時。具體來說,可以使用
    的頭像 發(fā)表于 11-06 11:05 ?6344次閱讀