Qt/C++ 中常用的几种高精度延时测试(其中三种Linux下可用)
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
Qt/C++ 中常用的几种高精度延时测试(其中三种Linux下可用)
这里博主统计了一下常见的几种延时方法,并做了一些延时精度测试,供大家参考:
- sleep()、msleep()、usleep()分别进行阻塞线程的时钟延时
- QWaitCondition::wait()+QMutex阻塞线程延时
- QEventLoop + QTimer非阻塞线程延时
- select()延时
- RTC硬件时钟计时
其中2、4、5种方法只在linux下可用。
新建子线程
/****************************************************************
Doc : timethread.h
Author : BingLee
Date : 2021-05-27
Info : Test high percision timer.
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef TIMETHREAD_H
#define TIMETHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class TimeThread : public QThread
{
Q_OBJECT
public:
TimeThread(QObject *parent = NULL);
void run();
void sleepMethod1(int time_ms); //sleep():/s msleep():/ms usleep():/us sleep函数是使调用sleep函数的线程休眠
void sleepMethod2(int time_ms); //wait():/ms wait是阻塞当前线程
void sleepMethod3(int time_ms); //QEventLoop + QTimer::singleShot:/ms 不阻塞线程,精度主要依靠QTimer精度
void sleepMethod4(int time_ms); //select():/ms linux 下通过select()函数控制延时,精度可达到us
private:
QMutex m_pMutex;
QWaitCondition m_waitCondition;
};
#endif // TIMETHREAD_H
方法一 msleep()
void TimeThread::sleepMethod1(int time_ms)
{
//此处可以用根据实际需要的精度选择sleep():/s msleep():/ms usleep():/us
msleep(time_ms);
return;
}
方法二 QWaitCondition::wait()+QMutex
void TimeThread::sleepMethod2(int time_ms)
{
m_pMutex.lock();
m_waitCondition.wait(&m_pMutex, time_ms);
m_pMutex.unlock();
return;
}
方法三 QEventLoop + QTimer
void TimeThread::sleepMethod3(int time_ms)
{
QEventLoop loop; //定义一个新的事件循环
QTimer::singleShot( time_ms, &loop, SLOT( quit() ) ); //创建单次定时器,槽函数触发循环退出
loop.exec(); //直到定时时间到,本循环被退出
}
方法四 select()
void TimeThread::sleepMethod4(int time_ms)
{
#if (defined Q_OS_LINUX)
struct timeval timeOut;
timeOut.tv_sec = 0; //延时单位/s
timeOut.tv_usec = 1000 * time_ms; //延时单位/us
select(1, NULL, NULL, NULL, &timeOut);
#else
msleep(time_ms);
#endif
return;
}
方法五 RTC硬件时钟
这里我借用两篇其他博主的文章,有兴趣可以自己测试下述代码
RTC机制利用系统硬件提供的Real Time Clock机制,通过读取RTC硬件/dev/rtc,通过ioctl()设置RTC频率,代码如下:
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
unsigned long i = 0;
unsigned long data = 0;
int retval = 0;
int fd = open ("/dev/rtc", O_RDONLY);
if(fd < 0)
{
perror("open");
exit(errno);
}
/*Set the freq as 4Hz*/
if(ioctl(fd, RTC_IRQP_SET, 1) < 0)
{
perror("ioctl(RTC_IRQP_SET)");
close(fd);
exit(errno);
}
/* Enable periodic interrupts */
if(ioctl(fd, RTC_PIE_ON, 0) < 0)
{
perror("ioctl(RTC_PIE_ON)");
close(fd);
exit(errno);
}
for(i = 0; i < 100; i++)
{
if(read(fd, &data, sizeof(unsigned long)) < 0)
{
perror("read");
close(fd);
exit(errno);
}
printf("timer\n");
}
/* Disable periodic interrupts */
ioctl(fd, RTC_PIE_OFF, 0);
close(fd);
return 0;
}
linux c的四种定时方式(sleep/usleep/select/ioctl)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h> // gettimeofday sleep usleep
#include <sys/types.h> // open
#include <sys/stat.h> // open
#include <fcntl.h> // open
#include <errno.h> // error
#include <unistd.h> // close
#include <linux/rtc.h> // rtc_commadn RTC_IRQP_SET / RTC_PIE_ON / RTC_PIE_OFF
#include <sys/ioctl.h> // ioctl
/**g++ -o timer_test time_test.cc*/
/* 定义log输出宏 */
#define DEB_LOG(fmat,...) printf("%s:%d_%s() "fmat"\n", \
__FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__)
/*设定时钟频率,频率可用范围是2~8192,一定要是2的n次方,8192时,一次约122微妙,*/
#define FREQ 8192
#define USEC_PER_SECOND 1000000
/*根据输入的等待待时间(毫秒),计算循环次数*/
#define CALC_CNT(millseconds) (millseconds * 1000.0 / USEC_PER_SECOND * FREQ + 0.5)
struct timeval tvs, tve;
void showTime(int startStop, long sleepT, const char* msg) {
if (1 == startStop) {
gettimeofday(&tvs, 0); // 记录定时器开始时间
} else {
gettimeofday(&tve, 0); // 记录定时器结束时间
DEB_LOG("%s: [%ldus] [%ldus]", msg, sleepT,
(tve.tv_sec - tvs.tv_sec) * 1000000LL
+ (tve.tv_usec - tvs.tv_usec));
}
}
/* * 打开RTC时钟设备
* freq: RTC 时钟的频率
* fd: 读取RTC时钟的fd * */
int openRTC(int freq, int* fd) {
/* 打开 RTC 时间设备 */
*fd = open("/dev/rtc", O_RDONLY);
if (*fd < 0) {
DEB_LOG("open /dev/rtc NG, errno=%d msg=%s", errno, strerror(errno));
return -1;
}
/* 设定 RTC 的时钟频率 2~8192Hz,最小精度为123微秒*/
if (ioctl(*fd, RTC_IRQP_SET, freq) < 0) {
DEB_LOG("ioctl(RTC_IRQP_SET)");
close(*fd);
return -1;
}
/* 启动 RTC 时钟 */
if (ioctl(*fd, RTC_PIE_ON, 0) < 0) {
DEB_LOG("ioctl(RTC_PIE_ON)");
close(*fd);
return -1;
}
return 0;
}
/* * 关闭RTC时钟设备
* fd: 读取RTC时钟的fd * */
void closeRTC(int fd) {
/* 关闭 RTC 时钟计时 */
ioctl(fd, RTC_PIE_OFF, 0);
/* 关闭 RTC 装置 */
close(fd);
}
/*使用ioctl的情况下的,计时器函数*/
int rtcTimer(int millseconds, int fd) {
int loopNum = CALC_CNT(millseconds);
unsigned long data = 0;
for (int i = 0; i < loopNum; i++) {
/*read一次的时间 = 1秒/时钟频率 (频率范围 2~8192,最小精度为123微秒)*/
if (read(fd, &data, sizeof(unsigned long)) < 0) {
return -1;
}
}
return 0;
}
int main(int argc, char* argv[]) {
int sleepMs = 3; // ms
int sleepLoop = 5000;
long sleepT = sleepMs * sleepLoop * 1000;
/*############## 使用实时时钟 RTC 做定时 ################*/
// 打开 RTC 时钟
int fd;
int ret = openRTC(FREQ, &fd);
if (0 != ret) {
DEB_LOG("openRTC error");
return -1;
}
/* 使用 RTC 时钟计时 */
showTime(1,sleepT,"ioctl RTC");
for (int i = 0; i < sleepLoop; ++i) {
rtcTimer(sleepMs, fd); /* 调用定时器函数 */
}
showTime(2,sleepT,"ioctl RTC");
closeRTC(fd); //关闭 RTC 时钟
return 0;
}
测试结果
对上边前四种方法在linux系统上做有一定负载的运行测试,结果如下:
这四种方法时钟的偏差基本都在1ms,稳定性来说QWaitCondition::wait()+QMutex
≈select()
>msleep()
>QEventLoop + QTimer
源码
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e
added ecosystem file for PM2 4 年前
5def40a3
Add host customization support for the NodeJS version 4 年前
更多推荐
已为社区贡献4条内容
所有评论(0)