C++ 计时器

news2025/1/25 9:19:15

文章目录

  • 一、简介
  • 二、实现代码
    • 2.1 windows平台
    • 2.2 C++标准库
  • 三、实现效果

一、简介

有时候总是会用到一些计时的操作,这里也整理了一些代码,包括C++标准库以及window自带的时间计算函数。

二、实现代码

2.1 windows平台

StopWatch.h

#ifndef STOP_WATCH_H
#define STOP_WATCH_H

#ifdef _WIN32
#	include <windows.h>
#else 
#	include <sys/time.h>
#endif

/// <summary>
/// 基于Windows平台提供的函数,进行时间计算
/// </summary>

class StopWatch
{
public:
	StopWatch(); // 计时器将自动开始
	~StopWatch();

	void  start();

	// 返回启动以来用户经过的时间(以秒为单位)。
	double elapsed() const;

private:

#ifdef WIN32
	LONGLONG  freq_;
	LONGLONG  start_count_;
#else
	timeval start_time_;
#endif

};

#endif


StopWatch.cpp

#include "StopWatch.h"
#include <iostream>

StopWatch::StopWatch() {
	start();		//开始计时
}

StopWatch::~StopWatch() {}

void StopWatch::start() {
#ifdef WIN32
	LARGE_INTEGER  largeInteger;
	// 获取高精度性能计数器的频率,这个频率通常以每秒的计数数来衡量。
	QueryPerformanceFrequency(&largeInteger);
	freq_ = largeInteger.QuadPart;

	//获取当前性能计数器的值,它表示自系统启动以来的计数次数。
	QueryPerformanceCounter(&largeInteger);
	start_count_ = largeInteger.QuadPart;
#else
	gettimeofday(&start_time_, 0);
#endif
}

template <class T>
inline T clip_precision(T v, int p) {
	float tmp = std::pow(10.0f, p);
	return (static_cast<int>(v * tmp) / tmp);
}

double StopWatch::elapsed() const {
#ifdef WIN32
	LARGE_INTEGER  largeInteger;
	QueryPerformanceCounter(&largeInteger);
	LONGLONG now_count = largeInteger.QuadPart;

	//计算已经经过的时间。
	//计算当前计数值与起始计数值之间的差值,然后将其除以频率来得到时间,以秒为单位。
	double time = (double)((now_count - start_count_) / static_cast<double>(freq_));
	return clip_precision(time, 6);		//保留小数的有效位数
#else
	timeval now;
	gettimeofday(&now, 0);
	double time = (now.tv_sec - start_time_.tv_sec) + (now.tv_usec - start_time_.tv_usec) / 1.0e6;
	return clip_precision(time, 2);
#endif
}

2.2 C++标准库

std::chrono::steady_clock类型

Timer.h

#pragma once

#define NOMINMAX
#undef min
#undef max

#include <chrono>
#include <stdexcept>

/// <summary>
/// 基于C++标准库时间函数,进行计时(支持跨平台使用)
/// </summary>

class Timer
{
public:
    Timer()
        : m_start(std::chrono::steady_clock::time_point::min())
    {
    }

    void clear()
    {
        m_start = std::chrono::steady_clock::time_point::min();
    }

    bool isStarted() const
    {
        return (m_start != std::chrono::steady_clock::time_point::min());       //最小时间点
    }

    void start()
    {
        //steady_clock 是一个专门用于测量时间间隔的时钟,
        //它提供了稳定的、不受系统时间调整影响的时间
        m_start = std::chrono::steady_clock::now();
    }

    std::int64_t getMs() const
    {
        if (!this->isStarted()) {
            throw std::runtime_error("计时器未启动!");
        }

        const std::chrono::steady_clock::duration diff = std::chrono::steady_clock::now() - m_start;
        return std::chrono::duration_cast<std::chrono::milliseconds>(diff).count();
    }

private:
    std::chrono::steady_clock::time_point m_start;
};

std::clock类型

BasicTimer.h

#ifndef TIMER_H
#define TIMER_H

#include <cfloat>

/// <summary>
/// 测量用户进程时间的计时器类, 它只计算处于
/// 运行状态(CPU执行)的时间, 时间信息以秒为单位给出。
/// </summary>

class BasicTimer
{
public:
	BasicTimer() : elapsed_(0.0), started_(0.0), interv_(0), running_(false) {}

	void	start();
	void	stop();
	void	reset();
	bool	is_running() const { return running_; }

	double	time()       const;
	int		intervals()  const { return interv_; }

	double	precision()  const;

private:
	double	user_process_time()     const; //秒
	double	compute_precision() const; //秒

	double	elapsed_;
	double	started_;
	int		interv_;
	bool	running_;

	static bool failed_;
};

#endif

BasicTimer.cpp

#include "BasicTimer.h"

#include <climits>
#include <ctime>
#include <cfloat>
#include <assert.h>
#include <cmath>

bool BasicTimer::failed_ = false;

template <class T>
inline T basic_timer_clip_precision(T v, int p) {
	float tmp = std::pow(10.0f, p);
	return (static_cast<int>(v * tmp) / tmp);
}

double BasicTimer::user_process_time() const {
	// 与操作系统相关。 返回一个单调增加的时间(以秒为单位)
	//(在溢出的情况下可能会回绕,请参阅 max()),
	// 如果该时间的系统调用失败,则返回 0.0。 
	// 如果系统调用失败,则设置静态标志“m_failed”。
	std::clock_t clk = std::clock();
	assert(clk != (std::clock_t)-1);
	if (clk != (std::clock_t)-1) {
		return double(clk) / CLOCKS_PER_SEC;
	}
	else {
		failed_ = true;
		return 0.0;
	}
}

double BasicTimer::compute_precision() const {
	// 动态计算计时器精度(以秒为单位)。
	double min_res = DBL_MAX;
	for (int i = 0; i < 5; ++i) {
		double current = user_process_time();
		if (failed_)
			return -1.0;
		double next = user_process_time();
		while (current >= next) {		// 等到计时器增加
			next = user_process_time();
			if (failed_)
				return -1.0;
		}
		// 获取所有运行的最小时间差。
		if (min_res > next - current)
			min_res = next - current;
	}
	return min_res;
}

double BasicTimer::precision() const {
	// 如果计时器系统调用失败,则第一次调用时计算精度返回 -1.0。
	static double prec = compute_precision();
	return prec;
}

void BasicTimer::start() {
	assert(!running_);
	started_ = user_process_time();
	running_ = true;
	++interv_;
}

void BasicTimer::stop() {
	assert(running_);
	double t = user_process_time();
	elapsed_ += (t - started_);
	started_ = 0.0;
	running_ = false;
}

void BasicTimer::reset() {
	interv_ = 0;
	elapsed_ = 0.0;
	if (running_) {
		started_ = user_process_time();
		++interv_;
	}
	else {
		started_ = 0.0;
	}
}

double BasicTimer::time() const {
	if (running_) {
		double t = user_process_time();
		return basic_timer_clip_precision(elapsed_ + (t - started_), 6);
	}

	return basic_timer_clip_precision(elapsed_, 6);
}

三、实现效果

测试:

#include <iostream>

#include "../StopWatch.h"
#include "../Timer.h"
#include "../BasicTimer.h"

int main()
{
	// ------------------------windows平台----------------------
	StopWatch stopWatch;
	stopWatch.start();

	// --------------------C++标准库(支持跨平台)---------------
	Timer timer;
	timer.start();

	BasicTimer basicTimer;
	basicTimer.start();

	for (int i = 0; i < 10000000; ++i)
	{
		//循环,用于计时
	}

	// ------------------------输出结果----------------------
	std::cout << "StopWatch 计时为:" << stopWatch.elapsed() << "s" << std::endl;
	std::cout << "Timer 计时为:" << timer.getMs() << "ms" << std::endl;
	std::cout << "BasicTimer 计时为:" << basicTimer.time() << "s" << std::endl;

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1681080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源的图形化Windows软件安装升级方案:WingetUI

WingetUI&#xff1a;简化数字生活&#xff0c;WingetUI让软件管理轻松便捷- 精选真开源&#xff0c;释放新价值。 概览 WingetUI是在GitHub上开发的一个实用工具&#xff0c;专为Windows用户设计&#xff0c;旨在为常见的命令行包管理工具&#xff08;如Winget、Scoop、Pip、…

计算机毕业设计hadoop+hive+hbase学情分析 在线教育大数据 课程推荐系统 机器学习 深度学习 人工智能 大数据毕业设计 知识图谱

毕 业 设 计&#xff08;论 文&#xff09;开 题 报 告 1&#xff0e;结合毕业设计&#xff08;论文&#xff09;课题情况&#xff0c;根据所查阅的文献资料&#xff0c;每人撰写不少于1000字的文献综述&#xff1a; 一、研究背景和意义 “互联网”和大数据带来了网络教育的蓬…

API数据对接:本地缓存与日志记录的重要性

关键词&#xff1a;数据治理项目、API接口、数据中心、第三方系统、数据异常、本地缓存、日志记录、数据整合、多源异构数据、数据处理效率 阅读建议&#xff1a; 对于数据治理、API接口和系统集成领域的专业人士&#xff0c;本文深入剖析了本地缓存和日志记录在确保系统稳定性…

信息系统项目管理师0601:项目立项管理 — 考点总结(可直接理解记忆)

点击查看专栏目录 项目立项管理 — 考点总结(可直接理解记忆) 1.项目建议书(又称立项申请)是项目建设单位向上级主管部门提交项目申请时所必须的文件,是对拟建项目提出的框架性的总体设想。在项目建议书批准后,方可开展对外工作(掌握)。 2.项目建议书应该包括的核心内…

系统架构师考试(一)

瀑布模型&#xff08;SDLC&#xff09; 特点&#xff1a; 1、严格区分阶段&#xff0c;每个阶段因果关系紧密相连 2、只适合需求明确的项目 需求分析之后会产出软件需求规格说明书SRS 但是这个模型失败概率到95%&#xff0c;有以下缺陷&#xff1a; 它只适合需求明确的项目…

Spring Boot | Spring Boot 中 自定义“用户退出控制“、获取“登录用户信息“

目录: 一、SpringBoot 中 自定义 "用户授权管理" ( 总体内容介绍 ) :二、 自定义 "用户退出控制" ( 通过 "HttpSecurity类" 的 logout( )方法来实现 "自定义用户用户登录控制" ) :1.基础项目文件准备2.实现 "自定义身份认证"…

Java入门基础学习笔记25——死循环和循环嵌套

死循环&#xff1a; 可以一直执行下去的一种循环&#xff0c;如果没有干预不会停下来。 死循环的写法&#xff1a; 例&#xff1a; package cn.ensource.loop;public class EndLessLoopDemo5 {public static void main(String[] args) {// 目标&#xff1b;掌握死循环的写法w…

GitHub配置SSH协议|什么是SSH

前言 之前用云服务器和GitHub的时候&#xff0c;因为比较懒一直没有配置过ssh。随着最近项目的迫在眉睫&#xff0c;通过Vs Code链接服务器和从GitHub白嫖代码的频率的大幅增加&#xff0c;拒绝接触新事物鼠鼠我只好转求ssh。此篇文章记录了我自己创建ssh密钥、配置ssh密钥的步…

什么是网络端口?为什么会有高危端口?

一、什么是网络端口&#xff1f; 网络技术中的端口默认指的是TCP/IP协议中的服务端口&#xff0c;一共有0-65535个端口&#xff0c;比如我们最常见的端口是80端口默认访问网站的端口就是80&#xff0c;你直接在浏览器打开&#xff0c;会发现浏览器默认把80去掉&#xff0c;就是…

python批量生成防伪识别二维码

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.代码 三.使用 四.总结 一.前言 二维码(QR Code)是一种矩阵条码技术,它使用黑白矩形图案来表示二进制数据,这些矩形图案可以被设备扫描并解读。二维码可以被用来存储

Spring数据访问全攻略:从JdbcTemplate到声明式事务

上文讲到 —— 航向数据之海&#xff1a;Spring的JPA与Hibernate秘籍 本文目录 四. JdbcTemplate的使用定义JdbcTemplate及其在Spring中的作用展示如何使用JdbcTemplate简化数据库操作1. 配置JdbcTemplate2. 使用JdbcTemplate查询数据3. 打印查询结果 五. Spring的事务管理介绍…

Linux进程(三) --- 状态和优先级

运行&#xff0c;阻塞&#xff0c;挂起 运行 (Running) 当一个进程处于运行状态时&#xff0c;它正在使用CPU执行指令。进程在以下两种情况下可能被认为是运行状态&#xff1a; 实际运行&#xff08;Running on CPU&#xff09;&#xff1a; 进程当前正在CPU上执行。可运行&…

ES6之数值的扩展

1. 数值的扩展 1.1. 二进制和八进制字面量表示:1.2. 数值判断方法: 1.2.1. Number.isFinite() 检查一个值是否为有限的数值。1.2.2. Number.isNaN() 更准确地检测NaN值。1.2.3. 传统的全局方法 isFinite() 和 isNaN() 的区别 1.3. 数值转换方法:1.4. 整数检查与精度: 1.4.1. Nu…

UDP多对多组播通信

广播和多播仅应用于UDP。TCP是一个面向连接的协议&#xff0c;TCP一定是点对点的&#xff0c;一点是两个主机来建立连接的&#xff0c;TCP肯定是单播。只有UDP才会使用广播和组播。 如下示例实现一个UDP多对多的组播通信&#xff0c;进程中有收、发两个线程&#xff0c;分别表…

数字水印 | 奇异值分解 SVD 的定义、原理及性质

目录 1 为什么使用 SVD&#xff1f;2 SVD 的定义是什么&#xff1f;2.1 特征值分解2.2 奇异值分解 3 如何求解奇异值 SV&#xff1f;3.1 求解过程3.2 证明过程 4 什么是 SVD 的性质&#xff1f; 参考博客&#xff1a; Python 机器学习笔记&#xff1a;奇异值分解&…

Java入门基础学习笔记23——For循环结构

1、for循环&#xff1a; 控制一段代码反复执行很多次。 2、For循环语句的基本结构&#xff1a; for(初始化表达式&#xff1b;判断表达式&#xff1b;递增&#xff08;递减&#xff09;表达式&#xff09; {循环体语句&#xff08;重复执行的代码&#xff09; } 例&#xff1…

积温空间分布数据、气温分布数据、日照数据、降雨量分布、太阳辐射数据、地表径流数据、土地利用数据、npp数据、ndvi数据

引言 积温是某一时段内逐日平均气温之和,它是研究植物生长、发育对热量的要求和评价热量资源的一种指标,是影响植物生长的重要因素之一&#xff0c;对指导农业生产和生态建设具有非常重要的意义。作为重要的气候资源&#xff0c;积温与其它资源的区别在于存在很大的地域差异和时…

【再探】设计模式—桥接模式、组合模式及享元模式

结构型设计模式描述了对象与类之间的关系。适配器模式及装饰器模式主要用于接口适配及功能增强&#xff0c;而桥接模式模式则是为了减少类的数量&#xff0c;组合模式让部分与容器能被客户端统一对待处理&#xff0c;享元模式则是用于节约系统内存&#xff0c;提高系统性能。 …

kk聊天室系统源码搭建-自适应手机电脑-秒级响应-群体消息

kk聊天室系统源码搭建-自适应手机电脑-秒级响应-群体消息-单体消息 可以无限创建聊天室&#xff0c;可以把单个聊天室链接拿出来单独使用&#xff0c;消息秒级响应&#xff0c;支持设置屏蔽词。 具体仔细看视频演示&#xff0c;不提供演示&#xff0c;因为青狐资源网会员用户太…

第25次修改留言板,修改了布局,样式和脚本分离

伤心城市 首页 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"beiwanglu" content"widthdevice-width, initial-scale1.0"><link rel"stylesheet" type&qu…