Qt:如果只有一个编写器线程,我是否需要互斥体?

Qt: do I need a mutex if there is only one writer thread?

配置:调试结果:程序退出,代码为 0。

配置:释放结果:主线程无限循环,不会跳出循环(t.n==0为真)

我怎样才能摆脱困境?

只有一个编写器线程,所以我没有使用任何互斥锁。

qt5.13 vs2017

main.cpp:

//#include"QtTestProg.h"
#include<QApplication>
#include<QMessageBox>
#include<QThread>
class MyThread :public QThread
{
    Q_OBJECT
public:
    int n = 0, m = 1;
    void run()override;
};
void MyThread::run()
{
    for (; m;) {
        QThread::msleep(3000);
        n = 1;
    }
}
int main(int argc, char*argv[])
{
    QApplication a(argc, argv);
    MyThread t;
    t.start();
    for (; 1;)
    {
        if (t.n != 0)
        {
            break;
        }
    }
    t.m = 0;
    t.quit();
    t.wait();
    return 0;
}
#include"main.moc"

这个循环:

    for (; 1;)
    {
        if (t.n != 0)
        {
            break;
        }
    }

从技术上讲,即使编译器发现 t.n 没有被修改,上面的代码也可以永远 运行。从理论上讲,它可以将值缓存在寄存器中或对其进行优化。还有与进行无锁编程相关的缓存一致性问题。

三个选项:

  1. 使用std::atomic在单个变量上具有快速的类锁和线程安全语义。

  2. 只需在 t.n 的赋值和计算周围使用一个 std::mutex and std::lock

  3. 使用 condition variable 这样主线程会等待 n 发生变化,直到 运行ning 线程发信号通知它已经发生变化。

Only one writer thread,so I didnot use any mutex.

这是未定义的行为。如果您从不同的线程读取和写入相同的内存位置,则需要同步。来自 https://en.cppreference.com/w/cpp/language/memory_model

When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless

  • both evaluations execute on the same thread or in the same signal handler, or
  • both conflicting evaluations are atomic operations (see std::atomic), or
  • one of the conflicting evaluations happens-before another (see std::memory_order)

If a data race occurs, the behavior of the program is undefined.

您要么需要一个保护读写的互斥锁,要么使用 std::atomic_int/QAtomicInt 而不是 mn 的普通 int

至于未定义行为的后果,here (godbolt) 您可以看到 O2 级别的 gcc 完全编译出 main() 中的循环,除非您将 TYPEint 到顶部的 std::atomic_int

您需要使用 QReadWriteLock。此 class 专为您的情况而设计,当您需要多个读者互不干扰时。