Qt:QMutex类

QMutex类提供线程之间的访问序列化。

头文件:

#include <QMutex>

cmake:

find_package(Qt6 COMPONENTS Core REQUIRED)
target_link_libraries(mytarget PRIVATE Qt6::Core)

qmake:

QT += core

详细说明

QMutex的目的是保护对象、数据结构或者代码段,以便每次只有一个线程可以访问它(这类似于Java synchronized关键字)。通常最好将QMutex和QMutexLocker一起使用,因为这样可以很容易的确保锁定和解锁一致的执行。

比如,有一个方法用两行向用户输出信息:

int number = 6;

void method1()
{
    number *= 5;
    number /= 4;
}

void method2()
{
    number *= 3;
    number /= 2;
}

如果这两个方法被连续调用,会发生以下情况:

// method1()
number *= 5;        // number is now 30
number /= 4;        // number is now 7

// method2()
number *= 3;        // number is now 21
number /= 2;        // number is now 10

如果这两个方法同时在两个线程中调用,那么结果可能如下:

// Thread 1 calls method1()
number *= 5;        // number is now 30

// Thread 2 calls method2().
//
// Most likely Thread 1 has been put to sleep by the operating
// system to allow Thread 2 to run.
number *= 3;        // number is now 90
number /= 2;        // number is now 45

// Thread 1 finishes executing.
number /= 4;        // number is now 11, instead of 10

如果我们添加了一个互斥锁,就会得到我们想要的结果:

QMutex mutex;
int number = 6;

void method1()
{
    mutex.lock();
    number *= 5;
    number /= 4;
    mutex.unlock();
}

void method2()
{
    mutex.lock();
    number *= 3;
    number /= 2;
    mutex.unlock();
}

这样,在任何给定的时间只有一个线程可以修改number,并且结果是正确的。当然,这是一个简单的示例,但适用于需要按特定顺序发生事情的任何其他情况。

当您在一个线程中调用lock()时,尝试在同一位置调用lock()的其他线程将阻塞,直到获得锁的线程调用unlock()。lock()的非阻塞替代方法是tryLock()。

QMutex经过优化,在非争用情况下速度更快。如果没有争用这个互斥锁,它将不会分配内存。它的构造和销毁几乎没有任何开销,这意味着将许多互斥对象作为其他类的一部分是可以的。

参见QRecursiveMutex、QMutexLocker、QReadWriteLock、QSemaphore和QWaitCondition。

成员函数

QMutex

QMutex::QMutex()

构造一个新的互斥锁。互斥锁是在未锁定状态创建的。

~QMutex

QMutex::~QMutex()

破坏了互斥锁。

警告:销毁一个锁定的互斥锁可能会导致未定义的行为。

lock

void QMutex::lock()

锁定互斥锁。如果另一个线程锁定了互斥锁,那么这个调用将会阻塞,直到该线程解锁了互斥锁。

在同一个线程的同一个互斥锁上多次调用这个函数将导致死锁。

tryLock

bool QMutex::tryLock(int timeout)

试图锁定互斥锁。如果获得了锁,这个函数返回true;否则返回false。如果另一个线程锁定了互斥锁,这个函数将等待最多毫秒的超时时间,以使互斥锁可用。

注意:传递一个负数作为timeout相当于调用lock(),也就是说,如果timeout为负数,这个函数将永远等待直到互斥锁被锁定。

如果获得了锁,那么在其他线程成功锁定互斥对象之前,必须先使用unlock()解除锁定。

在同一个线程的同一个互斥锁上多次调用这个函数将导致死锁

bool QMutex::tryLock()

这是一个重载函数。

试图锁定互斥锁。如果获得了锁,这个函数返回true;否则返回false。

如果获得了锁,那么在其他线程成功锁定互斥对象之前,必须先使用unlock()解除锁定。

在同一个线程的同一个互斥锁上多次调用这个函数将导致死锁。

try_lock

bool QMutex::try_lock()

试图锁定互斥锁。如果获得了锁,这个函数返回true;否则返回false。

提供这个函数是为了兼容标准库的概念可锁。它相当于tryLock()。

这个函数是在Qt 5.8中引入的。

try_lock_for

[since 5.8]
template <typename Rep, typename Period> bool QMutex::try_lock_for(std::chrono::duration<Rep, Period> duration)

试图锁定互斥锁。如果获得了锁,这个函数返回true;否则返回false。如果另一个线程锁定了互斥锁,这个函数将至少等待互斥锁可用的时间。

注意:传递负的持续时间相当于调用try_lock()。这种行为与tryLock()不同。

如果获得了锁,那么在其他线程成功锁定互斥对象之前,必须先使用unlock()解除锁定。

在同一个线程的同一个互斥锁上多次调用这个函数将导致死锁。

这个函数是在Qt 5.8中引入的。

请参阅lock()和unlock()。

try_lock_until

[since 5.8]
template <typename Clock, typename Duration> bool QMutex::try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)

试图锁定互斥锁。如果获得了锁,这个函数返回true;否则返回false。如果另一个线程锁定了互斥锁,这个函数将至少等待到互斥锁可用的时间点。

注意:传递一个已经传递的时间点等同于调用try_lock()。这种行为与tryLock()不同。

如果获得了锁,那么在其他线程成功锁定互斥对象之前,必须先使用unlock()解除锁定。

在同一个线程的同一个互斥锁上多次调用这个函数将导致死锁。

这个函数是在Qt 5.8中引入的。

unlock

void QMutex::unlock()

解除互斥锁。试图解锁另一个线程中的互斥锁,而锁定互斥锁的线程会导致错误。解锁未锁定的互斥锁将导致未定义的行为。