在 Qt Blocking Master 示例中使用 Mutex
Posted
技术标签:
【中文标题】在 Qt Blocking Master 示例中使用 Mutex【英文标题】:Use of Mutex in Qt Blocking Master example 【发布时间】:2018-06-18 08:23:08 【问题描述】:我正在研究Qt Blocking Master example 以了解使用Qt 进行串行通信。在此示例中,串行通信以同步方式完成,因此,为了保持 GUI 响应,创建了一个单独的(非 GUI)线程来处理串行通信。我不明白的是在负责通信的线程(即MasterThread
)中使用互斥锁来同步线程的部分:
注意,transaction() 方法是在主线程中调用的,但是 请求在 MasterThread 线程中提供。 MasterThread 数据 成员在不同的线程中同时读取和写入,因此 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();
[MasterThread 运行方法]
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 类可以 一次只处理一个请求。
我的问题:
我不明白 Mutex 的必要性。我的理由是只有一个线程(在Dialog
类中创建)处理通信,因此不存在竞争条件,也不需要同步。
我对上面引用的最后一句话更加困惑(即“在任何情况下......”)。 “[另一个] 进程获取数据”是什么意思?我们这里只有一个进程(即整个应用程序)和两个线程(一个用于 GUI,一个用于串行通信)并且这两个线程没有共享数据,这不是真的吗?为什么QString
的线程安全在这里很重要?
【问题讨论】:
【参考方案1】:我不明白 Mutex 的必要性。我的理由是只有一个线程(在 Dialog 类中创建)处理通信,因此没有竞争条件,也不需要同步。
应用程序从一个已经处于活动状态的线程开始。那是gui线程。只要您启动其他线程,就会有多个 线程。如果通信线程与其他线程隔离,它将毫无用处。一旦不再隔离,就需要一种同步访问共享数据的方法,并且必须共享一些数据——这就是没有隔离的定义。取消隔离线程的唯一方法是共享一些数据(如果不使用操作系统或硬件可能提供的低级消息传递功能 - 在这里,它不是)。
同步在 gui 线程和通信线程之间。 transaction()
方法必须是线程安全的,即它必须使用一些同步原语 - 这里是互斥体。
“[另一个] 进程获取数据”是什么意思?
进程在特定句子中用作线程的不幸同义词。
为什么这里 QString 的线程安全很重要
QString
的线程安全很重要,因为一个特定的QString
实例一次只能从一个线程访问,即不支持并发。甚至不支持读取并发 - 有些人认为仅仅因为他们不修改数据,只读访问是线程安全的。除非明确指定,否则不会。具体来说,在这种情况下:在线程 1 中读取给定的 QString
,并在线程 2 中写入它,会导致未定义的行为,这不是假设。你会破坏东西。
这两个线程没有共享数据
进程的线程都在同一个地址空间,因此默认共享数据。因此需要同步原语。同步可能是隐式的,例如如果线程通过发布事件进行通信,则事件队列是同步原语:它将从事件发布者到事件接收者的访问序列化,即针对给定线程的事件发布者与该线程中的接收者同步。
【讨论】:
感谢您的回答。让我更清楚的另一件事是,我认为transaction
方法是在MasterThread
线程中执行的,这是错误的,因为它是在主线程中执行的。而这正是你提到的解除隔离发生的地方。以上是关于在 Qt Blocking Master 示例中使用 Mutex的主要内容,如果未能解决你的问题,请参考以下文章
如何在Qt Creator中使两个小部件相互连接并相互调整大小[重复]