Qt同步线程

本文介绍了Qt中用于线程同步的几个关键类,包括QMutex、QMutexLocker、QReadWriteLock及其用法。QMutex提供了锁住和解锁互斥量的方法,QMutexLocker简化了互斥量的管理,QReadWriteLock支持多个读线程并发访问资源,而QSemaphore则提供了计数信号量的功能。通过这些工具,开发者可以有效地避免多线程环境下数据的不一致性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击看原文

Qt同步线程

我们知道,多线程有的时候是很有用的,但是在访问一些公共的资源或者数据时,需要进行同步,否则会使数据遭到破坏或者获取的值不正确。Qt提供了一些类来实现线程的同步,如QMutex,QMutexLocker,QReadWriteLock,QReadLocker,QWriteLocker,QSemaphore和QWaitCondition。下面我们分别来看它们的用法:

QMutex

首先,简单的了解一下QMutex提供的函数。

构造函数:QMutex ( RecursionMode mode = NonRecursive )。

需要注意的是构造函数的参数,RecursionMode 递归模式。枚举类型RecursionMode 有两个值:

QMutex::Recursive,在这个模式下,一个线程可以多次锁同一个互斥量。需要注意的是,调用lock()多少次锁,就必须相应的调用unlock()一样次数解锁。

QMutex::NonRecursive(默认),在这个模式下,一个线程只能锁互斥量一次。

void QMutex::lock ()

该函数用来锁住一个互斥量。如果另外的线程已经锁住了互斥量,函数将被阻塞等待另外的线程解锁互斥量。

如果是一个可递归的互斥量,则可以从同一个线程多次调用这个函数,如果是非递归的互斥量,多次调用这个函数将会引发死锁。我们来看看源码是怎么实现的。

复制代码

void QMutex::lock()

{
   

  QMutexPrivate *d = static_cast<QMutexPrivate*>(this->d);

  Qt::HANDLE self;

  if(d->recursive) {
   

    self = QThread::currentThreadId();

    if(d->owner == self) {
   

    ++d->count;             //同一个线程多次lock时,仅仅自增count

    //当然递归次数太多也会导致栈溢出

    Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflowin recursion counter");

    return;

  }

  bool isLocked = d->contenders.testAndSetAcquire(0, 1);

  if(!isLocked) {
   

    // didn'tget the lock, wait for it

    isLocked = d->wait();

    Q_ASSERT_X(isLocked, "QMutex::lock",

    "Internalerror, infinite wait has timed out.");

  }

  d->owner = self;          //递归模式时,owner记录拥有互斥量的线程

  ++d->count;             //记录lock的次数

  Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflowin recursion counter");

  return;

}

//非递归模式时,

  bool isLocked = d->contenders.testAndSetAcquire(0, 1);   //尝试加锁

  if(!isLocked) {
   

    lockInternal();  //加锁失败则在lockInternal()中一直等到别的线程解锁。

  }

}

看看lockInternal的实现

void QMutex::lockInternal()

{
   

。。。

do {
   

。。。。//其他代码太复杂,感觉最重要的就是这个while循环了,

//一直循环检测,试图加锁。这我们就好理解,非递归模式的//互斥量,不要在同一个线程里,多次调用lock了。因为第二次调用的时候会在

//这里死循环了

} while(d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1));

。。。。。。。

}

复制代码

bool QMutex::tryLock ()

该函数试图锁一个互斥量,如果成功则返回true。如果另外的线程已经锁住了互斥量,函数直接返回false。

bool QMutex::tryLock ( int timeout )

该函数跟上面的trylock()相似。不同的是,如果互斥量在别的线程锁住的情况下,函数会等待timeout 毫秒。需要注意的是,如果传入的timeout 为负数,函数将无限期等待,跟调用lock()一样的效果。这个函数跟上面的差不多,所以只看该函数的源码实现就好了。

复制代码

bool QMutex::tryLock(inttimeout)

{
   

    QMutexPrivate *d = static_cast<QMutexPrivate*>(this->d);

    Qt::HANDLE self;

    if(d->recursive) {
   

        self = QThread::currentThreadId();

        if(d->owner == self) {
   

          ++d->count;

          Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");

        return true;

    }

    boolisLocked = d->contenders.testAndSetAcquire(0, 1);

    if(!isLocked) {
   

        // didn'tget the lock, wait for it

        isLocked = d->wait(timeout);    //尝试加锁失败则等待

        if(!isLocked)

        return false;

    }

    d->owner = self;

    ++d->count;

    Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");

    return true;

}

//尝试加锁失败,(d->contenders.testAndSetAcquire(0,1)返回false,所以继续执行d->wait(timeout);

return (d->contenders<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值