QBasicAtomicInt在哪个库里5

在gemfield的《从pthread到QThread》一文中我们了解了線程的基本使用但是有一大部分的内容当时说要放到这片里讨论,那就是线程的同步问题关于这个问题,gemfield在《从进 程到线程》中有一個比喻有必要重新放在下面温习下:

最后用一个比喻来总结下:
1、一个进程就好比一个房子里有一个人;
2、clone创建线程就相当于在这个房孓里添加一个人;
3、fork创建进程就相当于再造一个房子,然后在新房子里添加一个人;

有了上面的比喻后我们就清楚很多了:
1、线程之间囿很多资源可以共享:比如厨房资源、洗手间资源、热水器资源等;
2、而对于进程来说,一个概念就是进程间通信(你要和另外一个房子裏的人通信要比一个房子里的两个人之间通信复杂);
3、线程之间因为共享内存所以通过一个全局的变量就可以交换数据了;
4、但与此哃时,对于线程来说又有新的概念产生了:
a、一个人使用洗手间的时候,得锁上以防止另一个人对洗手间的访问;
b、一个人(或几个人)睡觉的时候另外一个人可以按照之前约定的方式来叫醒他;
c、热水器的电源要一直开着,直到想洗澡的人数减为0;

上面的概念在gemfield的後文中术语化的时候,你就不会再觉得很深奥或者枯燥了
对于上面的a:一个人使用洗手间的时候,得锁上以防止另一个人对洗手间的访問我们在QThread里使用的就是QMutext这个互斥了。mutex是mutual exclusion(互相排斥)的简写在pthread中也有pthread_mutex_*族,但是在QThread中我们能在Qt的框架下通过看到具体实现所以pthread_mutex_*就靠你洎行研究了。

第一部分、QMutex的研究

2、如何解决这个问题

很明显我们想要一个线程(比如线程1)在访问变量number的时候,除非该线程(比如线程1)允许否则其他线程(比如线程2)不能访问number;这就好比一个人访问洗手间,另一个人就无法访问一样(我们把对number的访问区域或者洗手间這个区域称作临界区域);下面就是QMutex的使用:

在QMutex的使用中,我们关注以下4个方法和2个属性:

另外两个属性是:递归和非递归如果这个mutex是递歸的话,表明它可以被一个线程锁多次也就是锁和解锁中再嵌套锁和解锁;非递归的话,就表明mutex只能被锁一次

这四个的用法已经在上媔的代码中展示过了,现在来看看QMutex是怎么做到这一点的

3、QMutex是如何做到保护临界区域的?

设想一下我们的洗手间问题:洗手间提供了什么機制让一个人在使用的时候,另一个人无法闯入门锁!现在开始我们的QMutex之旅:

a、首先得构造出一个QMutex对象吧,要了解这一点我们得先叻解下QMutex的类型层次及成员。

从上面的类型层次可以看出这个接口是QBasicMutex类实现的,如下:

对不起了各位,我刚洗了个澡回来我发现照这樣写下去本文就写不完了。我决定把本文介绍的内容的底层实现部分放在《Qt的原子操作》一文之后本文从简介绍下互斥、读写锁、条件變量、信号量这些概念及用法。所以上面红颜色装饰的内容就先不要看了。

QMutexLocker相当于QMutex的简化提供了简化了的互斥上的操作(也即简化了嘚加锁和解锁)。

虽然互斥的功能保证了临界区资源的安全但是在某些方面并不符合实际;比如一般情况下,资源可以被并发读!举个實际的例子:有一本书(比如CivilNet BOOK)当某个人读到一页时,另外一个人(或者多个人)也可以过来读;但是当1个人往上面写笔记时,其他囚不能一起写而且只有这个人把笔记写完了,再让大家一起看

QReadWriteLock的作用就是保证各个线程能并发的读某个资源,但是要写的话就得真嘚lock了(所以,QReadWriteLock适合大量并发读偶尔会有写的情况);代码如下:

反过来,QMutex是QSemaphore的特殊情况QMutex只能被lock一次,而QSemaphore却可以获得多次;当然了那昰因为Semaphores要保护的资源和mutex保护的不是一类;Semaphores保护的一 般是一堆相同的资源; 比如:
1、mutex保护的像是洗手间这样的,只能供1人使用的资源(不是公共场所的洗手间);
2、Semaphores保护的是像停车场、餐馆这样有很多位子资源的场所;

比如对于一个停车场来说一般会在停车场的入口用个LED指礻牌来指示已使用车位、可用车位等;你要泊车进去,那就要acquire(1)了这样available()就会减一;如果你开车离开停车场 ,那么就要release(1)了同时available()就会加一。

讓gemfield用代码来演示一个环形缓冲区和其上的信号量(生产-消费模型):

服务员(producer)要生产1000份涮肉( DataSize) 当他要把生产好的一份涮肉往环形桌孓上放之前,必须使用freePlace信号量从环形桌上获得一个空地方(一共就100个)。 如果消费 者吃的节奏没跟的上的话QSemaphore::acquire() 调用可能会被阻塞。

最后服務员使用usedPlace信号量来释放一个名额。一个“空的位置”被成功的转变为“已被占用的位置”而这个位置消费者正准备吃。

对于食客(消费鍺)来说:

在main函数中gemfield创建了2个线程,并且通过QThread::wait()来确保在程序退出之前线程都已经执行完了(也即完成了各自的1000次for循环)

初始的时候,呮有服务员线程可以做任何事; 消费者线程被阻塞了——等待着usedPlace信号量被释放(available()初始值是0);当服务员把第一份涮肉放到桌子上的时候,

在一个多處理器的机器上这个程序将有可能达到基于mutex的程序的2倍快, 因为两个线程可以同时工作在不同的缓冲区上。

在服务员将肉放到环形桌上之湔先要检查下桌子是不是放满了。如果满了服务员就等待placeNotFull条件.

另外, 从locked状态到wait状态是原子的,以此来防止竞态条件的发生

在一个多处悝器的机器上,这个程序将有可能达到基于mutex的程序的2倍快, 因为两个线程可以同时工作在不同的缓冲区上

备注:本文属于gemfield的CivilNet博客()[Qt乐园]蝂块,转载此文时请保证包括备注在内的本文的完整性。

}

我要回帖

更多关于 库里 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信