在项目中,我需要在控制台中读取到对应的输出信息后,对事件进行延迟处理,这里我首先想到用msleep休眠函数,代码如下:
connect(RestoreFactoryProcess,&QProcess::readyReadStandardOutput,this,[this,&RestoreFactoryLoop,&RestoreFactoryData,&IfRestoreFactorySuccess,&RestoreFactoryProcess,&IfRestore,&qstrl]()
{
//读取通道内所有内容
RestoreFactoryData=QString::fromLocal8Bit(RestoreFactoryProcess->readAllStandardOutput());
qstrl<<RestoreFactoryData;
QString slToStr=qstrl.join("");
AddLog.AddLogText(RestoreFactoryData.toStdString());
int count = 0;
//判断是否恢复出场设置
if(RestoreFactoryData.contains("json_cmd 3"))
{
QThread::msleep(3000);
eventloop.exec();
AddLog.AddLogText("restore success");
IfRestoreFactorySuccess = true;
IfRestore = true;
RestoreFactoryProcess->close();
RestoreFactoryProcess->kill();
RestoreFactoryLoop.quit();
}
}
但此时运行软件会出现如下问题:在检测到包含json_cmd 3后,软件会直接闪退,此时我想会不会是QThread的msleep函数对多进程造成了影响,于是我去网上搜索了相应的问题。
以下是问题解析:
在Qt中,QThread::msleep()
是用来让当前线程休眠指定毫秒数的函数,通常用于处理异步任务,避免主线程阻塞。然而,在readyReadStandardOutput
这个信号连接上直接使用 msleep
可能会导致问题。
readyReadStandardOutput
是当标准输出(如控制台)中有数据可用时,会发送的一个信号。如果你在线程中接收到这个信号,并且立即使用 msleep
,可能会造成以下问题:
-
阻塞事件循环:如果主线程正在等待这个信号,而你又让该线程睡眠,这可能导致主线程无法响应其他输入和UI更新,最终可能导致用户界面冻结,用户体验变差。
-
资源泄露:长时间的休眠可能导致线程资源(比如锁或者其他全局资源)无法及时释放,进而影响其他线程的正常工作。
-
潜在的死锁:在某些情况下,如果其他线程正试图访问同一资源并持有互斥锁,而你的线程在休眠,那么可能会形成死锁。
为了避免这类问题,你应该在处理完readyReadStandardOutput
中的数据后再考虑是否需要暂停线程,或者将IO操作与线程睡眠分开,确保主线程的流畅性。如果确实需要线程暂停,可以考虑使用更合适的同步机制,例如条件变量(QWaitCondition
)或者将IO操作移动到新的单独线程中。
于是解决方法就简单了,既然有安全隐患,那就不用这种方法了,于是我采用了事件循环机制来实现延迟处理,运行软件发现不会再闪退了。
connect(RestoreFactoryProcess,&QProcess::readyReadStandardOutput,this,[this,&RestoreFactoryLoop,&RestoreFactoryData,&IfRestoreFactorySuccess,&RestoreFactoryProcess,&IfRestore,&qstrl]()
{
//读取通道内所有内容
RestoreFactoryData=QString::fromLocal8Bit(RestoreFactoryProcess->readAllStandardOutput());
qstrl<<RestoreFactoryData;
QString slToStr=qstrl.join("");
AddLog.AddLogText(RestoreFactoryData.toStdString());
int count = 0;
//判断是否恢复出场设置
if(RestoreFactoryData.contains("json_cmd 3"))
{
//QThread::msleep(3000);readyReadStandardOutput中使用可能会导致软件崩溃
QEventLoop eventloop;
QTimer::singleShot(5000, &eventloop, SLOT(quit()));
eventloop.exec();
AddLog.AddLogText("restore success");
IfRestoreFactorySuccess = true;
IfRestore = true;
RestoreFactoryProcess->close();
RestoreFactoryProcess->kill();
RestoreFactoryLoop.quit();
}
}
通过使用一个事件循环,达到延迟5秒的实现效果,创建步骤如下:
- 创建事件循环
- 启动定时器,让其100ms后触发事件循环的quit()槽
- 启动事件循环
所以在处理进程相关的代码里,还是要注意一些休眠函数的问题的,比如msleep,如果放在函数开头或结尾,是不会出现软件崩溃问题的,但如果是放在QProcess::readyReadStandardOutput中,可能会导致相应的信号处理出现异常,从而导致程序崩溃。