由于QCoreApplication事件循环,QThread永远不会退出 [英] QThread never quits due to QCoreApplication event loop

查看:576
本文介绍了由于QCoreApplication事件循环,QThread永远不会退出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个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()信号连接到我的QCoreApplicationquit()插槽没有意义.所以我最终使用的是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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆