现代c++中实现精确延时方法总结

简介: 现代c++中实现精确延时方法总结

程序中实现延时有很多种办法,但是有些不建议用。比如还在用sleep()或者空转计数的方式延时?要么移植性不好,要么不够精确且效率太低。这里总结下现代c++中推荐的一种实现精确延时的方法。



之前的一些用法


粗暴空转


long wait = 0;
while(wait  < 1000)
wait++;


这种非常不建议用,懒人做法。不够精确且换种环境系统处理速度不一样可能就是bug来源。


使用sleep()


#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
  cout <<"a";
    // 先输出a,再等2秒(2000毫秒),再输出a
  Sleep(2000);
  cout <<"a";
  return 0;
}


一般的平台或系统环境都带sleep()函数,可以实现简单的延时。但是这种延时不能指望精确,且最小精度1ms都难以保证。而且这种用法也不能跨平台,Windows下是大写字母开头的Sleep(),单位为毫秒,linux下面是小写的sleep()。Linux下的sleep()函数是以秒为单位的,sleep(1)就是休眠1秒,想实现更短的休眠,linux下有usleep()函数。


使用计时函数clock()


clock() 函数是 C 标准库 time.h 中的一个函数, time.h 标准库中定义了各种涉及日期和时间的函数, 变量类型和宏. 其中, clock() 函数可以返回自程序开始执行到当前位置为止, 处理器走过的时钟打点数(即"ticks", 可以理解为"处理器时间").


每过千分之一秒(即 1 毫秒)则 clock() 函数的返回值加 1. 但是, 处理器的时钟打点数并不是一个人类可以直观感知的时间概念, 时钟打点数只描绘了该处理器在处理该问题时所耗费的"处理器时间". 为了能将获取到的时间转换成便于人类理解且具有普遍性的"时 分 秒"的计时方式, 我们需要引入一个常量,在 Windows下使用常量 CLOCKS_PER_SEC 来进行转换且 CLOCKS_PER_SEC=1000.


在linux环境CLOCKS_PER_SEC  的值被定义成 1000000.


void delay()
{
    clock_t start_time;//, cur_time;
    start_time = clock();//clock()返回当前时间
    for (; (clock() - start_time) < 0.5 * CLOCKS_PER_SEC;);//延迟0.5秒
}


使用clock()函数也可以实现延时,通用性稍好些且能做到精确,但是也只能精确到1ms,常用它来测量某段代码的运行耗时用。


#include <time.h>
void test1(){
    clock_t start, stop;
    /*
    定义记录开始和结束时间的变量.
    clock_t 是 clock() 函数的返回变量类型.
    */
    double duration;
    /*
    记录函数运行时间
    */
    start=clock();
    printf("start=%d\n",start);
    for(int i = 0; i< 100000000; i++){
        ;
    }
    stop=clock();
    printf("stop=%d\n",stop);
    duration=((double)(stop-start))/CLOCKS_PER_SEC;
    //将时钟打点数转换成人类可以直观感知的时间秒数.
    printf("CLOCKS_PER_SEC=%d\n",CLOCKS_PER_SEC);
    printf("duration=%f\n",duration);
}


使用c++11之后的线程休眠函数


C++ 11之前并未提供专门的休眠函数。c语言的sleep、usleep其实都是系统提供的函数,不同的系统函数的功能还有些差异。从C++11开始,中C++标准库提供了专门的线程休眠函数,使得你的代码可以独立于不同的平台,sleep的时间间隔从纳秒到小时都有具体的定义。


比如我们想要一个线程休眠100ms:


#include <iostream>
#include <chrono>
#include <thread>
int main() {
   std::cout << "Hello waiter\n" << std::flush;
   auto start = std::chrono::high_resolution_clock::now();
   std::this_thread::sleep_for(std::chrono::milliseconds(2000));
   auto end = std::chrono::high_resolution_clock::now();
   std::chrono::duration<double, std::milli> elapsed = end-start;
   std::cout << "Waited " << elapsed.count() << " ms\n";
   std::this_thread::sleep_for(std::chrono::milliseconds(100));
}


推荐的用法


千呼万唤始出来,以下才是现在c++推荐的实现精确延时的用法。


#include <chrono>
void delay(int timeout_ms)
{
  auto start = std::chrono::system_clock::now();
  while (true)
  {
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
    if (duration > timeout_ms)
    {
      LOGGING_ERROR("timeout occurred,timeout %d ms", timeout_ms);
      break;
    }
}


引用


C / C++ 中的计时函数: clock()_荒原之梦网的博客-CSDN博客


std::chrono::high_resolution_clock简单测试 - 知乎


C++11 新的计时方法——std::chrono 大法好_一只牛_007的博客-CSDN博客


C++11新特征8 - 时钟与计时器 - 知乎


c++11 日期和时间工具-(std::chrono::steady_clock)(std::chrono::high_resolution_clock)_繁星璀璨G的博客-CSDN博客

相关文章
|
7月前
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
103 9
|
6月前
|
算法 Linux C++
C++框架设计中实现可扩展性的方法
在软件开发中,可扩展性至关重要,尤其对于C++这样的静态类型语言。本文探讨了在C++框架设计中实现可扩展性的方法:1) 模块化设计降低耦合;2) 使用继承和接口实现功能扩展;3) 通过插件机制动态添加功能;4) 利用模板和泛型提升代码复用;5) 遵循设计原则和最佳实践;6) 应用配置和策略模式以改变运行时行为;7) 使用工厂和抽象工厂模式创建可扩展的对象;8) 实现依赖注入增强灵活性。这些策略有助于构建适应变化、易于维护的C++框架。
499 2
|
3月前
|
编译器 API C语言
超级好用的C++实用库之跨平台实用方法
超级好用的C++实用库之跨平台实用方法
44 6
|
3月前
|
JavaScript 前端开发 Java
通过Gtest访问C++静态、私有、保护变量和方法
通过Gtest访问C++静态、私有、保护变量和方法
96 0
|
4月前
|
C++
C++ 避免多重定义的方法
C++ 避免多重定义的方法
65 0
|
4月前
|
Dart API C语言
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
|
6月前
|
C++ 存储 Java
C++ 引用和指针:内存地址、创建方法及应用解析
'markdown'C++ 中的引用是现有变量的别名,用 `&` 创建。例如:`string &meal = food;`。指针通过 `&` 获取变量内存地址,用 `*` 创建。指针变量存储地址,如 `string *ptr = &food;`。引用不可为空且不可变,指针可为空且可变,适用于动态内存和复杂数据结构。两者在函数参数传递和效率提升方面各有优势。 ```
|
6月前
|
存储 编译器 程序员
C++语言速成方法
C++语言速成方法
|
6月前
|
C++ UED 开发者
逆向学习 MFC 篇:视图分割和在 C++ 的 Windows 窗口程序中添加图标的方法
逆向学习 MFC 篇:视图分割和在 C++ 的 Windows 窗口程序中添加图标的方法
89 0
|
6月前
|
C++ 安全
高效遍历:C++中分隔字符串单词的3种方法详解与实例
拷贝并交换(Copy-and-Swap)是C++中实现赋值操作符和异常安全拷贝构造函数的技巧。它涉及创建临时对象,使用拷贝构造函数,然后交换数据以确保安全。C++11之前的策略在此后及C++11引入的移动语义和右值引用下仍有效,但后者提供了更高效的实现方式。