C++系列
- 第一章 C++单例模式
- 第二章 数据流对象CData
- 第三章 基于基础数据类型的封解包模板
- 第四章 FIFO单链列表
- 第五章 C++线程
- 第六章 C++线程池
- 第七章 定时器
- 第八章 消息中心
- 第九章 网络访问器
- 第十章 HttpClient
- 第十一章 FTPClient
- 第十二章 Socket客户端
- 第十三章 Socket服务端
- 第十四章 WebSocket
大部分章节不会详细讲解,基本是以源码形式展现给大家,欢迎各路大侠搬砖和点评^_^,详细源码查看Github
前言
有过使用Objective-C、Java等语言开发项目的同学会发现,网络或社区有存在众多的开源库或组件。个人在使用C++11进行项目开发时,想找一些比较完善、系统化的基本功能库却很少,比如定时器。
这里,主要利用thread、mutex、condition_variable_any、function来实现定时器,可现实同步、异步、单次、循序执行任务。代码中附带了简单的注释,若有疑问或建议欢迎留言。
更新时间 | 更新内容 |
---|---|
2021.03.17 | 1、新增时间戳相关静态接口;2、优化代码 |
CTimer.hpp
//
// CTimer.hpp
// ZJCrossCpp
//
// Created by eafy on 2020/10/5.
// Copyright © 2020 ZJ. All rights reserved.
//
#ifndef CTimer_hpp
#define CTimer_hpp
#include <stdio.h>
#include <functional>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <string>
#include <condition_variable>
#include "CDefType.hpp"
ZJ_NAMESPACE_BEGIN
class CTimer
{
public:
CTimer(const std::string sTimerName = ""); //构造定时器,附带名称
~CTimer();
/**
开始运行定时器
@param msTime 延迟运行(单位ms)
@param task 任务函数接口
@param bLoop 是否循环(默认执行1次)
@param async 是否异步(默认异步)
@return true:已准备执行,否则失败
*/
bool Start(unsigned int msTime, std::function<void()> task, bool bLoop = false, bool async = true);
/**
取消定时器,同步定时器无法取消(若任务代码已执行则取消无效)
*/
void Cancel();
/**
同步执行一次
#这个接口感觉作用不大,暂时现实在这里
@param msTime 延迟时间(ms)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template<typename callable, typename... arguments>
bool SyncOnce(int msTime, callable&& fun, arguments&&... args) {
std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...)); //绑定任务函数或lambda成function
return Start(msTime, task, false, false);
}
/**
异步执行一次任务
@param msTime 延迟及间隔时间(毫秒)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template<typename callable, typename... arguments>
bool AsyncOnce(int msTime, callable&& fun, arguments&&... args) {
std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
return Start(msTime, task, false);
}
/**
异步执行一次任务(默认延迟10毫秒后执行)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template<typename callable, typename... arguments>
bool AsyncOnce(callable&& fun, arguments&&... args) {
std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
return Start(1, task, false);
}
/**
异步循环执行任务
@param msTime 延迟及间隔时间(毫秒)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template<typename callable, typename... arguments>
bool AsyncLoop(int msTime, callable&& fun, arguments&&... args) {
std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
return Start(msTime, task, true);
}
public:
/// 获取时间戳(毫秒)
static uint64_t Timestamp();
/// 获取格式化时间
static std::string FormatTime(const std::string sFormat = "%Y-%m-%d %H:%M:%S");
/// 获取UTC时间
static struct tm *UTCTime(long long secTime = 0);
/// 获取UTC时间(秒)
static int64_t UTCTime();
/// 获取与0时区的时差(以秒为单位)
static int TimeDifFrimGMT();
private:
void DeleteThread(); //删除任务线程
public:
int m_nCount = 0; //循环次数
int m_nTag = 0; //定时器标签
private:
std::string m_sName; //定时器名称
std::atomic_bool m_bExpired; //装载的任务是否已经过期
std::atomic_bool m_bTryExpired; //装备让已装载的任务过期(标记)
std::atomic_bool m_bLoop; //是否循环
std::thread *m_Thread = nullptr;
std::mutex m_ThreadLock;
std::condition_variable_any m_ThreadCon;
};
ZJ_NAMESPACE_END
#endif /* CTimer_hpp */
CTimer.cpp
//
// CTimer.cpp
// ZJCrossCpp
//
// Created by eafy on 2020/10/5.
// Copyright © 2020 ZJ. All rights reserved.
//
#include "CTimer.hpp"
#include <future>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
ZJ_NAMESPACE_BEGIN
CTimer::CTimer(const std::string sTimerName):m_bExpired(true), m_bTryExpired(false), m_bLoop(false)
{
m_sName = sTimerName;
}
CTimer::~CTimer()
{
m_bTryExpired = true; //尝试使任务过期
DeleteThread();
}
bool CTimer::Start(unsigned int msTime, std::function<void()> task, bool bLoop, bool async)
{
if (!m_bExpired || m_bTryExpired) return false; //任务未过期(即内部仍在存在或正在运行任务)
m_bExpired = false;
m_bLoop = bLoop;
m_nCount = 0;
if (async) {
DeleteThread();
m_Thread = new std::thread([this, msTime, task]() {
if (!m_sName.empty()) {
#if (defined(__ANDROID__) || defined(ANDROID)) //兼容Android
pthread_setname_np(pthread_self(), m_sName.c_str());
#elif defined(__APPLE__) //兼容苹果系统
pthread_setname_np(m_sName.c_str()); //设置线程(定时器)名称
#endif
}
while (!m_bTryExpired) {
m_ThreadCon.wait_for(m_ThreadLock, std::chrono::milliseconds(msTime)); //休眠
if (!m_bTryExpired) {
task(); //执行任务
m_nCount ++;
if (!m_bLoop) {
break;
}
}
}
m_bExpired = true; //任务执行完成(表示已有任务已过期)
m_bTryExpired = false; //为了下次再次装载任务
});
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(msTime));
if (!m_bTryExpired) {
task();
}
m_bExpired = true;
m_bTryExpired = false;
}
return true;
}
void CTimer::Cancel()
{
if (m_bExpired || m_bTryExpired || !m_Thread) {
return;
}
m_bTryExpired = true;
}
void CTimer::DeleteThread()
{
if (m_Thread) {
m_ThreadCon.notify_all(); //休眠唤醒
m_Thread->join(); //等待线程退出
delete m_Thread;
m_Thread = nullptr;
}
}
#pragma mark -
uint64_t CTimer::Timestamp()
{
uint64_t msTime = 0;
#if defined(__APPLE__) //iOS
if (__builtin_available(iOS 10.0, *)) {
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_nsec) / 1000000;
} else {
struct timeval abstime;
gettimeofday(&abstime, NULL);
msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_usec) / 1000;
}
#else
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_nsec) / 1000000; //需要强制转long long
#endif
return msTime;
}
std::string CTimer::FormatTime(const std::string sFormat)
{
time_t timep;
time (&timep);
char tmp[64];
strftime(tmp, sizeof(tmp), sFormat.c_str(), localtime(&timep));
return std::string(tmp);
}
struct tm *CTimer::UTCTime(long long secTime)
{
time_t timep;
if (secTime) {
timep = secTime;
} else {
time (&timep);
}
struct tm *data = gmtime(&timep);
data->tm_year += 1900;
data->tm_mon += 1;
return data;
}
int64_t CTimer::UTCTime()
{
int64_t msTime = 0;
#if defined(__APPLE__) //iOS
if (__builtin_available(iOS 10.0, *)) {
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = ((int64_t)abstime.tv_sec) * 1000 + ((int64_t)abstime.tv_nsec) / 1000000;
} else {
struct timeval abstime;
gettimeofday(&abstime, NULL);
msTime = ((int64_t)abstime.tv_sec) * 1000 + ((int64_t)abstime.tv_usec) / 1000;
}
#else
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = (int64_t)abstime.tv_sec;
#endif
return msTime;
}
int CTimer::TimeDifFrimGMT()
{
time_t now = time(NULL);
struct tm *gmTime = gmtime(&now);
if (gmTime) {
return (int)difftime(now, mktime(gmTime));
}
return 0;
}
ZJ_NAMESPACE_END
用法:
- 方式1:
CTimer *pTimer = new CTimer("定时器1");
pTimer->AsyncOnce(10, [](void *userData) { //延迟10毫秒执行1次
CPCenterCtl *pCenterCtl = static_cast<CPCenterCtl*>(userData); //CPCenterCtl是当前类
if (pCenterCtl) {
CPrintf("这是一个定时器");
}
}, this);
- 方式2:
void CPCenterCtl::didHeartbeatThread(void *arg); //定时器任务函数
CTimer *pTimer = new CTimer("定时器2");
pTimer->AsyncLoop(10, didHeartbeatThread, this); //异步循环执行,间隔时间10毫秒
- 方式3:
CTimer *pTimer = new CTimer("定时器3");
pTimer->AsyncLoop(10, [](JMCPCenterCtl *self) {
printf(“这是一个10毫秒触发的定时器”);
}, this); //异步循环执行,间隔时间10毫秒
- 方式4:
int a = 1;
int b = 2;
int sum = 0;
CTimer *pTimer = new CTimer("定时器4");
pTimer->AsyncLoop(1000, [](void *self, int a, int b, int *sum) {
*sum = a + b + *sum;
printf("累加 sum += a + b + *sum: %d\n", *sum);
}, this, a, b , &sum); //异步循环执行,间隔时间1秒
打印:
累加 sum += a + b + *sum: 3
累加 sum += a + b + *sum: 6
累加 sum += a + b + *sum: 9
累加 sum += a + b + *sum: 12