QMutex

  QMutex类提供线程间的访问序列化。更多… |属性|内容| |-|-| |头文件|#include<QMutex>| |qmake|QT += core| |子类|QRecursiveMutex|

注意: 此类中所有函数都是线程安全的。

公共成员类型

类型 名称
enmu RecursionMode { Recursive, NonRecursive}

公共成员函数

返回类型 函数
QMutex(QMutex::RecursionMode mode)
QMutex()
~QMutex()
bool isRecursive() const
void lock()
bool tryLock(int timeout = 0)
bool try_lock()
bool try_lock_for(std::chrono::duration\ duration)
bool try_lock_until(std::chrono::time_point\ timePoint)
void unlock()

详细描述

  QMutex的目的是保护对象、数据结构或代码段,以便一次只有一个线程可以访问它们(这类似于 Java synchronized 关键字)。最好通过 QMutexLocker 来使用互斥量,这样可以很方便确保成对执行锁和解锁。 例如,假设有一个方法将消息打印到两行上:

  1. int number = 6;
  2. void method1()
  3. {
  4. number *= 5;
  5. number /= 4;
  6. }
  7. void method2()
  8. {
  9. number *= 3;
  10. number /= 2;
  11. }

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

  1. // method1()
  2. number *= 5; // number 30
  3. number /= 4; // number 7
  4. // method2()
  5. number *= 3; // number 21
  6. number /= 2; // number 10

  如果两个线程同时调用这两个方法,则可能会产生以下结果:

  1. // 线程 1 调用 method1()
  2. number *= 5; // number 30
  3. // 线程 2 调用 method2().
  4. //
  5. // 很可能线程 1 已被操作系统置于等待队列
  6. // 操作系统运行线程 2
  7. number *= 3; // number 90
  8. number /= 2; // number 45
  9. // 线程 1 执行完毕
  10. number /= 4; // number 是 11,而不是 10

  如果我们添加一个互斥量,我们就能得到我们想要的结果:

  1. QMutex mutex;
  2. int number = 6;
  3. void method1()
  4. {
  5. mutex.lock();
  6. number *= 5;
  7. number /= 4;
  8. mutex.unlock();
  9. }
  10. void method2()
  11. {
  12. mutex.lock();
  13. number *= 3;
  14. number /= 2;
  15. mutex.unlock();
  16. }

  在任何给定的时间只有一个线程可以修改 number,并正确执行。虽然这只是一个微不足道的例子,但也适用于其他需要有序执行的地方。

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

  QMutex被优化为在非争用情况 ( the non-contended )下速度更快。如果互斥体上没有争用,非递归QMutex将不会分配内存。它的构造和销毁几乎没有任何开销,这意味着将互斥体作为类的一部分是很好的做法。

另请参阅: QRecursiveMutexQMutexLockerQReadWriteLockQSemaphoreQWaitCondition

成员类型文档

enum QMutex::RecursionMode

常量 描述
QMutex::Recursive 1   在这种模式下,一个线程可以多次锁定同一个互斥量,并且在调用相同数量的 unlock() 之前,互斥体不会被解锁。对于这种情况,您应该使用 QRecursiveMutex
QMutex::NonRecursive 0   在这种模式下,一个线程只能锁定一次。

另请参阅:QMutex(),QRecursiveMutex

成员函数文档

QMutex::QMutex(QMutex::RecursionMode mode)

  构造一个互斥量,初始状态为未上锁。

  如果 modeQMutex::Recursive,则线程可以多次锁定同一个互斥量,并且在调用相同数量的 unlock() 之前,互斥量不会被解锁。否则,线程只能锁定互斥量一次。默认值为 QMutex::NonRecursive

另请参阅: lock(),unlock()。


QMutex::QMutex()

  构造一个互斥量,初始状态为未上锁。


QMutex::~QMutex()

  析构。

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


bool QMutex::isRecursive() const

  如果互斥量是递归的,则返回 true

  在 Qt 5.7 引入该函数。


void QMutex::lock()

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

  如果该互斥量是递归互斥量,则允许在同一线程的同一互斥体上多次调用此函数。如果这个互斥量是非递归互斥量,则当该互斥量递归锁定时,这个函数将死锁。

另请参阅: unlock()。


bool QMutex::tryLock(int timeout = 0)

  尝试锁定互斥量。如果获得了锁,此函数返回 true;否则返回 false。如果另一个线程锁定了互斥量,则此函数最多将等待 timeout 毫秒,以尝试获取。

注意: 传递一个负数给 timeout 相当于调用 lock()。即,如果 timeout 为负数,这个函数将一直待,直到互斥量被锁定为止。

  如果获得了锁,则必须使用 unlock() 解锁,另一个线程才能成功锁定。

  如果该互斥量是递归互斥量,则允许在同一线程的同一互斥量上多次调用此函数。如果此互斥量是非递归互斥量,则当尝试递归锁定互斥量时,此函数将始终返回 false

另请参阅: lock(),unlock()。


bool QMutex::try_lock()

  尝试锁定互斥量。如果获得了锁,此函数返回 true;否则返回 false

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

  在 Qt 5.8 引入该函数。


template bool QMutex::try_lock_for(std::chrono::duration duration)

  尝试锁定互斥量。如果获得了锁,此函数返回 true;否则返回 false。如果另一个线程锁定了互斥量,则此函数最多将等待 duration 这么长时间,以尝试获取。

注意: 传递一个负数给 duration 相当于调用 try_lock()。此行为与 tryLock() 不同。

  如果获得了锁,则必须使用 unlock() 解锁,另一个线程才能成功锁定。

  如果该互斥量是递归互斥量,则允许在同一线程的同一互斥量上多次调用此函数。如果此互斥量是非递归互斥量,则当尝试递归锁定互斥量时,此函数将始终返回 false

  在 Qt 5.8 引入该函数。

另请参阅: lock(),unlock()。


template bool QMutex::try_lock_until(std::chrono::time_point timePoint)

  尝试锁定互斥量。如果获得了锁,此函数返回 true;否则返回 false。如果另一个线程锁定了互斥量,则此函数最多将等待 timePoint 这么长时间,以尝试获取。

注意: 传递一个负数给 timePoint 相当于调用 try_lock()。此行为与 tryLock() 不同。

  如果获得了锁,则必须使用 unlock() 解锁,另一个线程才能成功锁定。

  如果该互斥量是递归互斥量,则允许在同一线程的同一互斥量上多次调用此函数。如果此互斥量是非递归互斥量,则当尝试递归锁定互斥量时,此函数将始终返回 false

  在 Qt 5.8 引入该函数。

另请参阅: lock(),unlock()。


void QMutex::unlock()

  解锁互斥量。试图在不同线程中解锁互斥量会导致错误。解锁未锁定的互斥量会导致未定义的行为。

另请参阅: lock()。