由Qt::BlockingQueuedConnection引起的关闭Qt主页面而后台仍有进程残留

这篇具有很好参考价值的文章主要介绍了由Qt::BlockingQueuedConnection引起的关闭Qt主页面而后台仍有进程残留。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

BUG:由Qt::BlockingQueuedConnection引起的关闭Qt主页面而后台仍有进程残留

1、错误代码示例

首先我们看下下面的代码,可以思考一下代码的错误之处

/** BlockingQueueDeadLock.h **/
#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_BlockingQueueDeadLock.h"
#include <thread>

class BlockingQueueDeadLock : public QMainWindow
{
    Q_OBJECT

public:
    BlockingQueueDeadLock(QWidget *parent = nullptr);
    ~BlockingQueueDeadLock();

public slots:
	void RecvBlockingQueueSignal();
signals:
	void SendBlockingQueueSignal();

private:
	void startLoopTest();
	void stopLoopTest();
	void RunInThread();

private:
    Ui::BlockingQueueDeadLockClass ui;
	std::thread loopTest;
	bool m_StopFlag;
};

/** BlockingQueueDeadLock.cpp **/
#include "BlockingQueueDeadLock.h"
#include <qdebug.h>

BlockingQueueDeadLock::BlockingQueueDeadLock(QWidget *parent)
    : QMainWindow(parent)
	, m_StopFlag(false)
{
    ui.setupUi(this);
	startLoopTest();
	connect(this, &BlockingQueueDeadLock::SendBlockingQueueSignal,
		this, &BlockingQueueDeadLock::RecvBlockingQueueSignal, Qt::BlockingQueuedConnection);
}

BlockingQueueDeadLock::~BlockingQueueDeadLock()
{
	stopLoopTest();
}

void BlockingQueueDeadLock::RunInThread()
{
	qDebug("%1", std::this_thread::get_id());
	while (!m_StopFlag) {
		std::this_thread::sleep_for(std::chrono::microseconds(10));
		qDebug("signal thread: %1", std::this_thread::get_id());
		emit SendBlockingQueueSignal();
	}
}

void BlockingQueueDeadLock::RecvBlockingQueueSignal()
{
	qDebug("slot thread: %1", std::this_thread::get_id());
}

void BlockingQueueDeadLock::startLoopTest()
{
	m_StopFlag = false;
	loopTest = std::thread(&BlockingQueueDeadLock::RunInThread, this);
}

void BlockingQueueDeadLock::stopLoopTest()
{
	m_StopFlag = true;
	if (loopTest.joinable()) {
		loopTest.join();
	}
}

上面短短几十行代码竟会导致当我关闭Qt主页面时,后台的进程并没有完全退出。
blockingqueuedconnection,QT/QML,日常问题,qt,开发语言

2、原因分析

先使用转储工具获取当前后台进程的堆栈信息;右击后台进程->创建转储文件
blockingqueuedconnection,QT/QML,日常问题,qt,开发语言

这时会获得一个DMP文件,通过windbg分析该DMP文件,如下图所示
blockingqueuedconnection,QT/QML,日常问题,qt,开发语言

我们可以清晰的看到后台进程一直在等待join函数的退出;阅读源码分析join最终调用的时_Thrd_join这个接口,该接口是阻塞的,需要等待线程的主函数运行结束后才会返回。

也就是说我们RunInThread线程主函数迟迟没有结束。

BlockingQueueDeadLock::~BlockingQueueDeadLock()
{
	stopLoopTest();
}

void BlockingQueueDeadLock::RunInThread()
{
	qDebug("%1", std::this_thread::get_id());
	while (!m_StopFlag) {
		std::this_thread::sleep_for(std::chrono::microseconds(10));
		qDebug("signal thread: %1", std::this_thread::get_id());
		emit SendBlockingQueueSignal();
	}
}
void BlockingQueueDeadLock::stopLoopTest()
{
	m_StopFlag = true;
	if (loopTest.joinable()) {
		loopTest.join();
	}
}

线程的主函数就是一个while循环,在我们BlockingQueueDeadLock析构的时候会将标识符m_StopFlag置为true;按道理讲该while循环应该很快的结束并返回。

但是!但是!但是!我们是否忽略了emit这个信号发射的是如何connect的呢?

connect(this, &BlockingQueueDeadLock::SendBlockingQueueSignal,
		this, &BlockingQueueDeadLock::RecvBlockingQueueSignal, Qt::BlockingQueuedConnection);

非常非常奇怪的是为什么connect最后一个参数是Qt::BlockingQueuedConnection呢?我看到这个代码也会很奇怪,可能之前的开发者认为发送信号和接受信号的slot不在同一个线程吧!!

3、解决方案

奇怪的地方必有妖,没错就是Qt::BlockingQueuedConnection这里有问题。

先看Qt官方文档的解释:
blockingqueuedconnection,QT/QML,日常问题,qt,开发语言

非常明确的指出了发射的信号与接收的槽不能在同一个线程里,否者会导致应用死锁。

想要了解Qt BlockingQueuedConnection源码的同学可以看下面的文章:

14.QueuedConnection和BlockingQueuedConnection连接方式源码分析_Master Cui的博客-CSDN博客
blockingqueuedconnection,QT/QML,日常问题,qt,开发语言

明确的指出了使用BlockingQueuedConnection同一个线程时死锁的原因。

因此,我们只需要将Qt::BlockingQueuedConnection最后的参数去除,使用默认参数即可。

这就是我发现的Qt主界面关闭,而后台进程未释放的问题;还是由于后台进程中的某个线程没有释放,而该线程没有结束又是由于Qt::BlockingQueuedConnection死锁导致的。

4、总结

当前Qt主界面关闭,而后台进程未释放的原因有很多。这里只是展示了其中一个原因:后台进程中有线程未及时释放导致的,也为遇到同样问题的你提供一个思路。文章来源地址https://www.toymoban.com/news/detail-712620.html

到了这里,关于由Qt::BlockingQueuedConnection引起的关闭Qt主页面而后台仍有进程残留的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • win环境后台启动、关闭springBoot的jar包配置

    win环境后台启动、关闭springBoot的jar包配置是我们技术人员必备的技能,目前很多业务都要求部署到win环境,而且需要设置后台启动,一般通过bat格式的文件设置,今天我们详细分享一下: 首先如果简单的命令:java -jar demo.jar 启动是最简单的前台启动,并且一旦关闭窗口,服

    2024年02月16日
    浏览(36)
  • dedecms关闭mysql错误日志生成文件功能(防止暴露后台与管理员)

    织梦程序在mysql错误时会自动在data文件夹里生成一个 mysql_error_trace.inc 文件记录错误信息,很多时候这个文件的错误信息里有后台目录和管理员账号信息在里面,我们其实大部分时候都不会去看这个文件的,所以关闭它生成很有必要! 关闭方法 打开 /include/dedesql.class.php 和

    2024年02月03日
    浏览(42)
  • QT调用不同UI界面响应,对话框跳转到主页面UI,用信号与槽传递信息,两级信号传递

    在MainWindow界面有一个按键”新建”,点击后需要生成一个输入对话框,实例用到了processDialog类对象。 我新建一行数据完成后,需要更新MainWindow表格的视图,此时就需要调用写在MainWIndow下的函数MainWindow::showProcess(vectorPCB* readyQueue) 但是如果实例化一个MainWidow对象,此时修改的

    2024年02月12日
    浏览(56)
  • 使用vscode远程服务器,让代码在vscode关闭后也在服务器后台运行

    可以使用VScode的Remote-SSH插件来连接远程服务器,并在关闭了VScode后让训练代码在后台运行。 具体的步骤如下: 安装VScode和OpenSSH,确保你可以在本地终端使用ssh命令连接服务器。 在VScode的扩展页面搜索并安装Remote-SSH插件。 在VScode的左侧菜单栏选择SSH Targets,点击齿轮图标,

    2024年02月11日
    浏览(49)
  • C#winform 点叉叉按钮关闭一form窗体应用后,后台进程仍在运行的解决办法

    如果要解决“C#winform 点叉叉按钮关闭一form窗体应用后,后台进程仍在运行”的问题,可以直接点击目录跳转到3.4关闭窗体的多种方法。 前面为记录遇到该问题的一些过程。 之前用C#做了一个日志备份的窗体应用程序,最近把这个程序完善了一下,在窗体上显示了配置文件中

    2023年04月26日
    浏览(45)
  • qt之实现QMessageBox定时关闭效果

    效果如下: 其实很简单,代码如下:

    2024年02月16日
    浏览(33)
  • QT`实现鼠标超时未点击,窗口自动关闭

    QT 实现鼠标超时未点击,窗口自动关闭 前言 有的时候我们需要某些窗口实现超时自动关闭,但是Qt窗口一般是多部件堆叠而成,如果常规处理,对每一个部件进行鼠标点击事件处理显然不太合理,我个人参考了网上前辈的处理方法,通过直接重新实现 QApplication::notify 函数来

    2024年02月10日
    浏览(48)
  • QT 子窗体关闭或按钮返回父窗体(零基础保姆级)

    功能 父窗体点击按钮打开子窗体并隐藏父窗体,子窗体点击返回按钮或者关闭按钮后销毁自己并返回父窗体 效果展示 打开uidesigner 设计父窗体ui 建立子窗体 设计子窗体UI “subwidget.h” “subwidget.cpp” “widget.h” “widget.cpp”

    2024年02月11日
    浏览(37)
  • Qt系列——点击按钮关闭窗口的三种实现方式,附源码

    主要实现了点击QPushButton按钮,关闭窗口的功能。 简单设计界面如下,按钮名称如图中右侧红框中内容 源程序连接

    2024年02月11日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包