简体   繁体   中英

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

configuration:debug result: program exit with code 0.

configuration:release result: main thread infinite loops,wont jump out of the loop(tn==0 is true).

how can I get out of the loop?

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

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"

This loop:

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

Technically, the above code could literally run forever even if the compiler sees that tn is not getting modified. It could, theoretically, cache the value in a register or optimize it out. There's also the cache-coherency issue associated to doing lockless programming.

Three options:

  1. Use std::atomic to have a fast lock-like and thread safe semantics on a single variable.

  2. Just use a std::mutex and std::lock around the assignment and evaluation of tn .

  3. Use a condition variable such that the main thread waits for n to change until the running thread signals that it has changed.

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

That's undefined behavior. If you read and write the same memory location from different threads, you need synchronization. From 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.

You either need a mutex guarding both reads and writes or use std::atomic_int / QAtomicInt instead of plain int for m and n .

As for the consequences of the undefined behavior, here (godbolt) you can see that gcc at O2 level compiles out the loop in the main() entirely unless you change TYPE from int to std::atomic_int at the top.

You need to use QReadWriteLock . This class is designed for your cases, when you need several readers not to block each other.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM