问题
因此,我有一个CommandRetriever类,其中包含一些命令,并且应该在不同的线程上执行这些命令。

class CommandRetriever
{
    public:
        CommandRetriever();
        ~CommandRetriever();

        void addCommand( QString, Command* );
        void executeCommands();

    private:
        QMap<QString, Command*> m_commands;
};
addCommand将在m_commands中添加一个新条目。但是,这里是有问题的功能。
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()插槽用于处理需要处理的内容。
由于某种原因,我的doAsync()对象的rcon函数将被调用,但是线程永远不会退出...我的主类如下所示:
int main( int argc, char *argv[] )
{
    QCoreApplication app( argc, argv );
    CommandRetriever cr( addr, port );

    //cr.addCommand() ...

    cr.executeCommands();

    return app.exec();
}
我的工作程序对象(rcon)将输出其应有的结果。但是,即使我的工作对象发出了finished()信号,该线程仍然存在,并且我的应用程序从未完成。我之前连接了这样的信号:
QObject::connect( rcon, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
但是后来我得到了错误:QThread: Destroyed while thread is still running和段错误。
我最近发布了一个与我的线程相关的问题,解决方案是调用thread->wait(),但是,我看到如果我有一个事件循环,就不需要thread->wait(),这也不是一个合适的解决方案。使用当前代码,我没有收到任何错误,但是我的应用程序可以永远运行。我猜app.exec()事件循环正在无限运行,如果我是对的,如何正确关闭所有内容?

解决方案
正如thuga所说:

通过连接我的工作人员对象的finished()信号使我的应用退出,可以轻松实现这一点:
QObject::connect( rcon, SIGNAL( finished() ), app, SLOT( quit() ) );
但是,如果我有一个窗口或其他一些GUI元素,则更有意义,这样我就可以确切地知道何时需要关闭程序(例如,用户关闭主窗口)。
因为我正在运行多个线程,并且因为我的应用程序只是一个控制台应用程序,所以将线程的finished()信号连接到QCoreApplicationquit()插槽没有意义。所以我最终使用的是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
为了等待线程完成,我打电话:
QThreadPool::globalInstance()->waitForDone();
这将阻塞主线程,直到所有线程完成执行为止,这对于我的控制台应用程序更有意义。这也使代码变得更加整洁。
我也删除了main.cpp中的app.exec(),因为我不再需要QCoreApplication提供的事件循环。
我学到的是? QThread不是实现多线程的唯一方法。就我而言,使用QThreadPool更有意义,因为我不需要QThread的信号/插槽。另外,如果不需要,则不应使用QCoreApplication事件循环。大多数控制台应用程序将属于此类别。

资料来源
http://doc.qt.io/qt-5/qrunnable.html
http://doc.qt.io/qt-4.8/qthreadpool.html

最佳答案

如果您不告诉QCoreApplication对象退出,它将永远不会离开exec()函数。

您可以直接调用QCoreApplication::quit()插槽,也可以将信号连接到它。

...
connect(thread, SIGNAL(finished()), qApp, SLOT(quit()));
qApp是引用唯一应用程序对象的全局指针。与调用QCoreApplication::instance()相同。

10-02 05:10