QThread :: quit是否可以在正在运行的线程中使用

时间:2018-06-13 16:02:46

标签: c++ multithreading qt thread-safety qthread

所以我有以下情况:

我有一个运行eventloop的QThread(即没有自定义运行功能)。为了停止线程,我向该线程中的工作人员发送信号。然后,这个工作人员会进行清理等工作,并在某些时候完成并退出该线程。

我现在面临的问题是:如果我调用了工人停止方法然后立即等待线程完成它将永远不会这样做,因为工作人员完成信号没有被处理。代码:

class Worker {
signals:
    void done();

public slots:
    void stop() {
        //dummy code to illustrate what happens here:
        QTimer::singleShot(3000, this, &Worker::done);
    }
};

// in the main thread
auto thread = new QThread();
auto worker = new Worker();
worker->moveToThread(thread);
connect(worker, &Worker::done, thread, &QThread::quit); //implicitly a queued connection

// ...

QMetaObject::invokeMethod(worker, "stop", Qt::QueuedConnection);
thread->wait(); //blocks here forever, because the connect is queued

现在的问题显而易见了 - 因为我在主线程上阻塞了永远不能调用槽(因为排队连接)因此从不调用quit。但是,如果我只是直接从工作者调用QThread::quit(或QThread::exit)(或使用DirectConnection)那么就不再有问题,因为不再需要主线程的事件循环处理事件。

所以这里的实际问题是:这是允许的吗?我可以在实际线程中调用QThread::quit吗?或者这可以创建Race条件,死锁和其他类似的问题。该文档未将该方法标记为线程安全 - 但由QThread管理的线程可能是一个例外。

2 个答案:

答案 0 :(得分:2)

如果查看Qt源文件夹中的文件src/corelib/thread/qthread.cpp,您可以看到quit()的实施方式:

void QThread::quit()
{ exit(); }

....和QThread::exit()绝对是从线程本身内部调用的。所以答案是肯定的,可以在QThread的线程中调用quit()(尽管直接调用QThread::exit()可能更常见)。

答案 1 :(得分:1)

  

我可以在实际线程中调用QThread::quit吗?

问题实际上是倒退了!

由于此方法控制事件循环,并且事件循环绝对在线程上运行,因此默认的假设是它不是线程安全的方法,因此只能从线程,因为它控制通过QEventLoop实例化的QThread::run实例。该事件循环及其事件调度程序为QObject,并且最明确的是thread()等于所讨论的QThread实例。

但是这不会使QThread非常有用,因此QAbstractEventDispatcher::exit,因此QEventLoop::quitQThread::quit确实是线程安全的方法 - 你可以从任何地方调用它们,包括来自事件循环所在的线程以外的线程。事件循环和线程的方法都采取额外的预防措施来保护他们的状态免受竞争,因此"因此"几句话之前的部分是手动一点。