由于QCoreApplication事件循环,QThread永远不会退出 [英] QThread never quits due to QCoreApplication event loop
问题描述
所以我有一个CommandRetriever类,其中包含一些命令,并且应该在不同的线程上执行这些命令.
So I have a CommandRetriever class that holds some commands, and should execute these commands on different threads.
class CommandRetriever
{
public:
CommandRetriever();
~CommandRetriever();
void addCommand( QString, Command* );
void executeCommands();
private:
QMap<QString, Command*> m_commands;
};
addCommand
将在m_commands
中添加一个新条目.但是,这里是有问题的功能.
addCommand
will add a new entry into m_commands
. Here is the function in question, however.
void CommandRetriever::executeCommands()
{
for( auto iter : m_commands.keys() )
{
Command *cmd = m_commands.value( iter );
// Command, password //
RemoteConnection *rcon = new RemoteConnection( cmd, "" );
QThread *thread = new QThread();
rcon->moveToThread( thread );
QObject::connect( thread, SIGNAL( started() ), rcon, SLOT( doAsync() ) );
QObject::connect( rcon, SIGNAL( finished() ), thread, SLOT( quit() ) );
QObject::connect( rcon, SIGNAL( finished() ), rcon, SLOT( deleteLater() ) );
QObject::connect( thread, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
thread->start();
}
}
RemoteConnection
是我的工作线程. doAsync()
插槽用于处理需要处理的内容.
RemoteConnection
is my worker thread. The doAsync()
slot is what processes what needs to be processed.
由于某种原因,我的rcon
对象的doAsync()
函数将被调用,但是线程将永远不会退出...我的主类如下所示:
For some reason, my doAsync()
function for my rcon
object will be called, but the thread will never exit... my main class looks like this:
int main( int argc, char *argv[] )
{
QCoreApplication app( argc, argv );
CommandRetriever cr( addr, port );
//cr.addCommand() ...
cr.executeCommands();
return app.exec();
}
我的工作对象(rcon
)将输出其应有的输出.但是,即使我的工作对象发出了finished()
信号,该线程仍然存在,并且我的应用程序从未完成.我之前连接了这样的信号:
My worker objects (rcon
) will output what they're supposed to. However, even though my worker objects emit a finished()
signal, the thread still lives, and my application never finishes. I connected a signal like this before:
QObject::connect( rcon, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
但是后来我得到了错误:QThread: Destroyed while thread is still running
和段错误.
But then I got the error: QThread: Destroyed while thread is still running
and a seg fault.
我最近发布了一个与我的线程相关的问题,解决方案是调用thread->wait()
,但是,我看到如果我有一个事件循环,则不需要thread->wait()
,并且它不是适当的解决方案.使用当前代码,我没有收到任何错误,但是我的应用程序可以永远运行.我猜想app.exec()
事件循环正在无限运行,如果我是对的,该如何正确关闭所有内容?
I recently posted a question that had a related issue to my threads, and the solution was to call thread->wait()
, however, I saw that if I have an event loop, thread->wait()
is not needed, and is not an appropriate solution. With the current code, I get no error, but my application runs forever. I'm guessing the app.exec()
event loop is infinitely running, and if I'm right, how can I shut everything down correctly?
如thuga所说:
您需要告诉QCoreApplication退出,否则它将永远不会从exec函数返回.
You need to tell your QCoreApplication to quit, otherwise it will never return from the exec function.
这可以通过连接我的工作程序对象的finished()
信号以使我的应用退出来轻松实现:
This could easily be achieved by connecting a my worker object's finished()
signal to make my app quit:
QObject::connect( rcon, SIGNAL( finished() ), app, SLOT( quit() ) );
但是,如果我有一个窗口或其他一些GUI元素,则更有意义,这样我就可以确切地知道何时需要关闭程序(例如,用户关闭主窗口).
However, this makes more sense if I had a window or some other GUI elements so that I would be able to definitively know when I need to shut down my program (e.g. the user closes the main window).
因为我正在运行多个线程,并且由于我的应用程序只是一个控制台应用程序,所以将我线程的finished()
信号连接到我的QCoreApplication
的quit()
插槽没有意义.所以我最终使用的是QThreadPool
:
Because I was running multiple threads and because my application is only a console application, it didn't make sense to connect my thread's finished()
signal to my QCoreApplication
's quit()
slot. So what I ended up using was QThreadPool
:
void CommandRetriever::executeCommands()
{
// Quick iterate through the command map //
for( auto iter : m_commands.keys() )
{
Command *cmd = m_commands.value( iter );
// Command, password; start a new thread for a remote connection. //
RemoteConnection *rcon = new RemoteConnection( cmd, "" );
QThreadPool::globalInstance()->start( rcon );
}
}
应该注意,类RemoteConnection扩展了QRunnable
.
It should be noted that the class RemoteConnection extends QRunnable
.
为了等待线程完成,我打电话:
To wait for the threads to finish, I call:
QThreadPool::globalInstance()->waitForDone();
这将阻塞主线程,直到所有线程完成执行为止,这对我的控制台应用程序更有意义.这也使代码变得更加整洁.
This will block the main thread until all of the threads finish execution, which makes more sense for my console application. It also makes the code a hell of a lot cleaner.
我也删除了main.cpp中的app.exec()
,因为我不再需要QCoreApplication
提供的事件循环.
I also removed app.exec()
in my main.cpp because I no longer needed the event loop that QCoreApplication
provides.
我学到了什么? QThread
不是实现多线程的唯一方法.就我而言,使用QThreadPool
更有意义,因为我不需要QThread
的信号/插槽.另外,如果不需要QCoreApplication
事件循环,则不要使用它.大多数控制台应用程序都属于此类.
What I learned? QThread
isn't the only way to achieve multithreading. In my case, it makes more sense to use QThreadPool
because I didn't need the signals/slots of QThread
. Also, you shouldn't use the QCoreApplication
event loop if it is not needed. Most console applications will fall into this category.
http://doc.qt.io/qt-5/qrunnable.html
http://doc.qt.io/qt-4.8/qthreadpool.html
推荐答案
如果不告诉QCoreApplication
对象退出,它将永远不会离开exec()
函数.
If you don't tell your QCoreApplication
object to quit, it will never leave the exec()
function.
您可以直接调用QCoreApplication::quit()
插槽,也可以将信号连接到该插槽.
You can either call QCoreApplication::quit()
slot directly, or connect a signal to it.
...
connect(thread, SIGNAL(finished()), qApp, SLOT(quit()));
qApp
是引用唯一应用程序对象的全局指针.等同于调用QCoreApplication::instance()
.
qApp
is a global pointer referring to the unique application object. It's same as calling QCoreApplication::instance()
.
这篇关于由于QCoreApplication事件循环,QThread永远不会退出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!