在 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的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt3D 中使线框透明?

如何使用qt在mac中使标签窗口从顶部滑动?

如何在 Qt 设计器中使控件自动调整大小?

如何在Qt Creator中使两个小部件相互连接并相互调整大小[重复]

如何将 Windows SDK 与 Qt Creator 一起使用

如何在以下面板示例中使所有控件可见