QThread::quit 是否可以在 运行 线程中使用
Is QThread::quit usabled from within the running thread
所以我有以下情况:
我有一个 QThread 运行 是一个事件循环(即没有自定义 运行 函数)。为了停止线程,我向该线程中的工作人员发送了一个信号。然后这个工作人员进行清理等,并在某个时候完成并退出线程。
我现在面临的问题是:如果我调用 workers stop 方法然后立即等待线程完成,它永远不会这样做,因为 workers 完成信号没有得到处理。代码:
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
现在问题很明显了——因为我在主线程上阻塞了槽永远无法调用(因为排队的连接)因此永远不会调用退出。但是,如果我直接从 worker 中直接调用 QThread::quit
(或 QThread::exit
)(或使用 DirectConnection
),那么就没有问题了,因为不再需要主线程的事件循环处理事件。
所以这里的实际问题是:这允许吗?我可以从实际线程中调用 QThread::quit
吗?或者这会造成竞争条件、死锁和其他类似问题。文档没有将该方法标记为线程安全的 - 但由 QThread 管理的线程可能是一个例外。
如果您查看 Qt 源文件夹中的文件 src/corelib/thread/qthread.cpp
,您可以看到 quit()
是如何实现的:
void QThread::quit()
{ exit(); }
... 和 QThread::exit()
绝对是为了从线程本身内部调用。所以答案是肯定的,从 QThread 的线程中调用 quit()
很好(尽管直接调用 QThread::exit()
可能更常见一些)。
Can I call QThread::quit
from within the actual thread?
这个问题其实是倒过来的!
由于此方法控制事件循环,并且事件循环肯定在线程上运行,默认假设它不是线程安全方法,因此 只能在thread,因为它控制通过 QThread::run
实例化的 QEventLoop
实例。该事件循环及其事件调度程序是 QObject
并且它们的 thread()
绝对等于所讨论的 QThread
实例。
但这不会使 QThread
非常有用,因此 QAbstractEventDispatcher::exit
,因此 QEventLoop::quit
和 QThread::quit
确实是线程安全的方法 - 你可以从任何地方调用它们,包括从事件循环所在线程以外的线程调用它们。事件循环和线程的方法都采取了额外的预防措施来保护它们的状态免受竞争,所以几句话前的 "and thus" 部分有点手摇。
所以我有以下情况:
我有一个 QThread 运行 是一个事件循环(即没有自定义 运行 函数)。为了停止线程,我向该线程中的工作人员发送了一个信号。然后这个工作人员进行清理等,并在某个时候完成并退出线程。
我现在面临的问题是:如果我调用 workers stop 方法然后立即等待线程完成,它永远不会这样做,因为 workers 完成信号没有得到处理。代码:
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
现在问题很明显了——因为我在主线程上阻塞了槽永远无法调用(因为排队的连接)因此永远不会调用退出。但是,如果我直接从 worker 中直接调用 QThread::quit
(或 QThread::exit
)(或使用 DirectConnection
),那么就没有问题了,因为不再需要主线程的事件循环处理事件。
所以这里的实际问题是:这允许吗?我可以从实际线程中调用 QThread::quit
吗?或者这会造成竞争条件、死锁和其他类似问题。文档没有将该方法标记为线程安全的 - 但由 QThread 管理的线程可能是一个例外。
如果您查看 Qt 源文件夹中的文件 src/corelib/thread/qthread.cpp
,您可以看到 quit()
是如何实现的:
void QThread::quit()
{ exit(); }
... 和 QThread::exit()
绝对是为了从线程本身内部调用。所以答案是肯定的,从 QThread 的线程中调用 quit()
很好(尽管直接调用 QThread::exit()
可能更常见一些)。
Can I call
QThread::quit
from within the actual thread?
这个问题其实是倒过来的!
由于此方法控制事件循环,并且事件循环肯定在线程上运行,默认假设它不是线程安全方法,因此 只能在thread,因为它控制通过 QThread::run
实例化的 QEventLoop
实例。该事件循环及其事件调度程序是 QObject
并且它们的 thread()
绝对等于所讨论的 QThread
实例。
但这不会使 QThread
非常有用,因此 QAbstractEventDispatcher::exit
,因此 QEventLoop::quit
和 QThread::quit
确实是线程安全的方法 - 你可以从任何地方调用它们,包括从事件循环所在线程以外的线程调用它们。事件循环和线程的方法都采取了额外的预防措施来保护它们的状态免受竞争,所以几句话前的 "and thus" 部分有点手摇。