在Qt阻塞主机示例中使用互斥体

Use of Mutex in Qt Blocking Master example

本文关键字:Qt 主机      更新时间:2023-10-16

我正在研究Qt阻塞大师的例子,以了解使用Qt进行串行通信。在此示例中,串行通信以同步方式完成,因此,为了保持 GUI 响应,创建了一个单独的(非 GUI(线程来处理串行通信。我不明白的是负责通信的线程中使用互斥锁的部分(即MasterThread( 同步线程:

注意,transaction(( 方法是在主线程中调用的,但是 请求在主线程线程中提供。主线程数据 成员在不同的线程中同时读取和写入,因此 QMutex 类用于同步访问。

void MasterThread::transaction(const QString &portName, int waitTimeout, const QString &request)
{
QMutexLocker locker(&mutex);
this->portName = portName;
this->waitTimeout = waitTimeout;
this->request = request;
if (!isRunning())
start();
else
cond.wakeOne();
}

[主线程运行方法]

void MasterThread::run()
{
bool currentPortNameChanged = false;
mutex.lock();
QString currentPortName;
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
}
int currentWaitTimeout = waitTimeout;
QString currentRequest = request;
mutex.unlock();

在任何情况下都不应调用 transaction(( 方法 同时与获取数据的进程同时进行。注意,虽然 QString 类是可重入的,它不是线程安全的。因此,它不是 建议读取请求线程中的串行端口名称,以及 超时或请求另一个线程中的数据。MasterThread 类可以 一次只处理一个请求。

我的问题:

  1. 我不明白需要互斥体。我的推理是只有一个线程(在Dialog类中创建(处理通信,因此没有竞争条件,也不需要同步。

  2. 我对上面引用的最后一句话感到更困惑(即"在任何情况下......"(。"[另一个]进程获取数据"是什么意思?我们这里只有一个进程(即整个应用程序(和两个线程(一个用于 GUI,一个用于串行通信(,而这两个线程没有共享数据,这不是真的吗?为什么QString的线程安全在这里很重要?

我不明白需要互斥。我的推理是只有一个线程(在 Dialog 类中创建(处理通信,因此没有竞争条件,也不需要同步。

应用程序从一个已处于活动状态的线程启动。这就是 gui 线程。一旦启动其他线程,就会有多个线程。如果通信线程与其他线程隔离,它将毫无用处。一旦它不再被隔离,就需要一种同步访问共享数据的方法,并且必须共享一些数据 - 这就是没有隔离的定义。取消隔离线程的唯一方法是共享一些数据(如果未使用操作系统或硬件可能提供的低级消息传递功能 - 在这里,它没有(。

同步在 gui 线程和通信线程之间进行。transaction()方法必须是线程安全的,即它必须使用一些同步原语 - 这里为互斥锁。

"[另一个]进程获取数据"是什么意思?

该过程在特定句子中用作线程的不幸同义词。

为什么QString的线程安全在这里很重要

QString的线程安全性很重要,因为一次只能从一个线程访问特定的QString实例,即不支持并发性。甚至不支持读取并发 - 有些人认为仅仅因为他们不修改数据,只读访问就是线程安全的。除非明确指定,否则不会如此。具体来说,在这种情况下:在线程 1 中读取给定的QString,并在线程 2 中写入它,会导致未定义的行为,这不是假设的。你会破坏东西。

这两个线程没有共享数据

进程的线程都位于同一地址空间中,因此默认情况下共享数据。因此需要同步原语。同步可能是隐式的,例如,如果线程通过发布事件进行通信,则事件队列是同步原语:它将从事件发布者到事件接收器的访问序列化,即针对给定线程的事件发布者与该线程中的接收器同步。