跟我学c++中级篇—c++11时间库实现定时器和延时
这里面有一疑问的可以看一下下面的程序,对sleep_for和sleep_until的使用是延时和定时器的主要方式,它们都是延时,一个到点,一个停止一段。有的资料说sleep_for会导致整个进程的所有线程阻塞,但在标准文档写的是当前线程阻塞,下面的代码就可以验证是哪种。//sleep(1);i < 10;t1.join();t3.join();return 0;
一、C++11时间库
先简单介绍一下C++11中有三类时钟:
1、system_clock:可以理解为壁钟,可调整(向前或向后),是系统时间。它可以 与C语言风格的时间进行映射。
2、steady_clock:类似于秒表的单调时钟,只可增长不能修改,最适合进行时间间隔的测量。
3、high_resolution_clock:高精度的时钟(最小计次周期),不可以修改的,可以将其看做 steady_clock或system_clock 的高精度版的别名(gcc 的 libstdc++ 它是 system_clock ,对于 MSVC 它是 steady_clock ,而对于 clang 的 libc++ 它取决于配置)。对时长度量使用 steady_clock ,对壁钟时间使用 system_clock
此处不对C++11中的时钟进行详细分析,只关心几种应用方式,下面逐一说明分析。
二、应用的介绍
这里面有一疑问的可以看一下下面的程序,对sleep_for和sleep_until的使用是延时和定时器的主要方式,它们都是延时,一个到点,一个停止一段。有的资料说sleep_for会导致整个进程的所有线程阻塞,但在标准文档写的是当前线程阻塞,下面的代码就可以验证是哪种。
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void for_thread() {
this_thread::sleep_for(chrono::seconds(6));
cout << "sleep_for:" << this_thread::get_id() << " is start" << endl;
}
void loop_thread() {
//sleep(1);
for (int i = 0; i < 10; i++) {
cout << "loop thread:" << this_thread::get_id() << "cur value: " << i << endl;
}
}
void until_thread() {
using std::chrono::operator""s;
chrono::time_point t = std::chrono::steady_clock::now() + 3s;
this_thread::sleep_until(t);
cout << "sleep_until:" << this_thread::get_id() << "is start" << endl;
}
int main() {
thread t1(for_thread);
thread t2(loop_thread);
thread t3(until_thread);
t2.join();
t1.join();
t3.join();
return 0;
}
很多情况都需要实践操作一下,即使是操作的有问题,也可以 更好的理解问题本身和应用库的特点。
三、定时器应用
1、做定时器
void timerLoop() {
bool Continue = true;
while (Continue) {
Continue = timerCallback();//回调函数,也就是定时器定时触发的函数
if (Continue) {
m_timer.sleepUntil();//时间间隔
}
}
}
//间隔设置用下而把 方法
double freq = 30.0;//此值可动态调整
duration = duration_cast<std::chrono::duration<long, std::micro>>(microseconds((long long)round(1e6 / freq)));
//可以理解为时间轮的槽的长度
void sleepUntil() {
if (Done) {
clock::time_point nextSlot = begin + duration;
// sleep
std::this_thread::sleep_until(nextSlot);
} else {
Done = true;
}
begin = std::chrono::high_resolution_clock::now();
}
最初在学习定时器时,就不断看到说定时器其实就是一个独立的线程,现在自己实现一把,就更明白底层的实现了。原理基本都是类似的,重点在于两个,一个是写得要安全;另外一个是适应性要好。
2、延时(阻塞调用)
如果用在一种和需要阻塞一段时间才能拿到结果的API调用时,这种方法就有用了,以前好多人都是用死循环(硬件嵌入式比较多),但这种可能会使整个进程被占用。但在上层一般会用回调或者事件等方式来处理。不过总有一些情况需要延时,所以就可以 用这种来实现。如上面的函数:
void until_other() {
std::chrono::time_point<std::chrono::steady_clock> now;
now = std::chrono::steady_clock::now();
std::this_thread::sleep_until(now + std::chrono::milliseconds(1000)+ std::chrono::microseconds(100));
cout << "sleep_until_other:" << this_thread::get_id() << "is start" << endl;
}
sleep_for比较简单,就不举例了。
3、计时
先看一下传统的测量耗时的方法
struct timeval t1, t2;
double timeuse;
gettimeofday(&t1, NULL);
//此处调用函数,用来测试时间
gettimeofday(&t2, NULL);
timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) / 1000000.0;
printf("readmeme Use Time:%f\n", timeuse);
再看一个用C++11时间库的:
#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>
volatile int sink;
int main()
{
for (auto size = 1ull; size < 1000000000ull; size *= 100) {
// 记录开始时间
auto start = std::chrono::high_resolution_clock::now();
// 做一些工作
std::vector<int> v(size, 42);
sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
// 记录结束时间
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << "Time to fill and iterate a vector of "
<< size << " ints : " << diff.count() << " s\n";
}
}
还有一些细小的应用大家可以 在实际用到查一下文档即可。
四、总结
在C++11中利用时间库加线程就可以比较轻松的实现一个跨平台的定时器。这比在Linux的其它定时器的实现既简单又方便,精度也可以自己确定,这在一般的通用场合就足够了。简单就是王道,这个是无法比拟的。
最近总是有些想法想说一说。现在是知识爆炸的年代,许多技术知识在网上是可以很容易搜到的。但这些知识,有大牛给出的,有小牛给的,有经验丰富的开发者给的,更多的是一些应用者,甚至还有一些是初学者,把一些掌握的问题解法和知识心得发表到网上。这些技术或者解决技术难题的方法,从整体上看,相当多都只是某一方面上的,也可以说是很片面的。对不同的人群来说,可能这些知识所给予的心得各有不同。但从不同的角度来看,可能一些受众是初学者的,大牛们的文章反而短时间内不好消化吸收。学习终归是从点突破到线发展,最后到面扩展,到最终生成一个立体的知识球体也就是个人的认知体系,也是网上说的知识蚕茧。
有的人学习可能会是不断的打破这个茧,更多的人反而是强化这个茧。这就是牛人和非牛人的区别。说这么多是什么 意思呢?网上的知识被个体搜索到后,要有分辨能力,哪些能为我所用,哪些不能,哪些是正确的,哪些是错误的,哪些是片面的。网上的知识,很多是提供思路和灵感,不是说拷贝过来就用。要善于进行拿来主义,而不是僵化的拿来主义。要有哲学上否定之否定的思想,不断的总结和升华自己的知识体系,打破固有的知识牢笼或者说知识蚕茧。
学习永远在路上,变化才是永恒!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)