Qt同步线程

点击看原文

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<
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值