QTimer::singleShot导致定时器资源耗尽解决方法

参考文章:Qt QTimer::singleShot问题及用法

1. 问题描述

QTimer::singleShot定时器事件超时,如果此时类内对象已经被回收,定时器事件调用已经释放的类内资源时会引起崩溃。

这通常是因为定时器的回调函数(槽函数)在执行时可能会导致事件循环被阻塞,进而导致定时器无法正常触发,或者在高频率调用时,定时器的数量迅速增加,造成资源消耗过大。

QTimer::singleShot(100, this, [=]() {
	LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
	LOG(INFO) << QString::number(i).toStdString();
});

2. 百分百复现

可使用以下代码:

在while语句中不停使用QTimer::singleShot。

while (1)
{
	QTimer::singleShot(100, this, [=]() {
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
}

 

报错如图所示:

3. 解决方法1:使用QCoreApplication::processEvents()

while (1)
{
	QCoreApplication::processEvents();
	QTimer::singleShot(100, this, [=]() {
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
}

 QCoreApplication::processEvents() 是 Qt 框架中的一个函数,用于处理事件循环中的待处理事件。它的主要作用是使应用程序能够在某些情况下处理事件,比如用户输入、定时器超时等,而不会阻塞程序的执行。

QCoreApplication::processEvents() 的作用

  1. 处理事件:当调用 processEvents() 时,Qt 会处理所有待处理的事件,包括定时器事件。这意味着即使在某个长时间运行的操作中,定时器也有机会被触发,从而避免了定时器的回调函数无法执行的问题。

  2. 避免阻塞:如果在槽函数中执行了耗时的操作,调用 processEvents() 可以让事件循环继续运行,处理其他事件,防止应用程序因为一个长时间运行的操作而完全无响应。

  3. 释放资源:通过让事件循环处理其他事件,processEvents() 可以帮助释放一些资源,避免因为定时器未能及时触发而造成的资源泄漏。

4. 解决方法2:用定时器代替QTimer::singleShot

while (1)
{
	QTimer *t = new QTimer;
	connect(t, &QTimer::timeout, [=]() {
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
	t->setSingleShot(true);
	t->start(50);
}

while (1)
{
	QTimer *t = new QTimer;
	connect(t, &QTimer::timeout, [=]() {
		t->stop();
		t->deleteLater();
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
	t->start(50);
}

5. 解决方法3:设置interval为0

while (1)
{
	QTimer *t = new QTimer;
	t->singleShot(0, this,connect(t, &QTimer::timeout, [=]() {
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
}

while (1)
{
	QTimer::singleShot(0, this,connect(t, &QTimer::timeout, [=]() {
		LOG(INFO) << QString::fromLocal8Bit("____QTimer::singleShot testtest____").toStdString();
		LOG(INFO) << QString::number(i).toStdString();
	});
}

虽然这个方法可以使其不报错,但是因为设置interval为0,对于时间间隔为0的事件,甚至连QSingleShotTimer都不需要创建,而是直接用invokeMethod去调用相应的slot,所以定时器不算响应了。

参考文章:QTimer源码分析(以Windows下实现为例)_qtimer::singleshot源码及分析-CSDN博客

 

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值