QT线程(二)---线程同步
线程互斥
多线程运行时,通常会访问同一个变量,同一个数据结构,或者同一段代码。因此,需要使用互斥技术来保护上述资源,确保多线程执行的正确性。
注:
我们通常说某个函数是线程安全的,也就是因为该函数实现加入了线程互斥保护。
4.1、QMutex
|
QMutex ( RecursionMode mode = NonRecursive ) |
|
|
~QMutex () |
|
|
void |
lock () mutex加锁,如果当前其他线程已对该mutex加锁了,则该调用被阻塞直到其他线程释放该mutex。 |
|
bool |
tryLock () mutex加锁,和lock不同的是,如果当前其他线程已对该mutex加锁了,则该调用会立即返回,而不被阻塞。 |
|
bool |
tryLock ( int timeout ) 同tryLock,和tryLock不同的是,如果当前其他线程已对该mutex加锁了,则该调用会等待一段时间,直到超时或者其他线程释放了mutex。 |
|
void |
unlock () mutex解锁,释放被锁住的资源。 |
Mutex有两种模式,用户可以在构造函数参数中指定。
|
Constant |
Value |
Description |
|
QMutex::Recursive |
1 |
In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made. 该模式下,一个线程可以对mutex多次lock,直到相应次数的unlock,调用后,该mutex才真正被unlock。 |
|
QMutex::NonRecursive |
0 |
In this mode, a thread may only lock a mutex once. 该模式下,mutex只能被lock一次。 |
实例:
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();
}
4.1、QMutexLocker
|
QMutexLocker ( QMutex * mutex ) |
|
|
QMutex * |
mutex () const |
|
void |
relock () |
|
void |
unlock () |
QMutexLocker实际上是对QMutex使用的一种简化。
例如以下场景:
当某段代码存在多个分支,在对QMutex加锁后,需要在不同的分支路径下都执行解锁操作,才能保证Mutex关联的资源能被其他线程继续访问, 否则就出现死锁。
QMutexLocker接收一个QMutex作为参数,当创建QMutexLocker对象时,就对关联的Mutex进行了Lock操作,直到该QMutexLocker对象被销毁,相关的QMutex才被Unlock。
实例:
直接使用QMutex:
int complexFunction(int flag)
{
mutex.lock();
int retVal = 0;
switch (flag) {
case 0:
case 1:
mutex.unlock();
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0) {
mutex.unlock();
return -2;
}
retVal = status + flag;
}
break;
default:
if (flag > 10) {
mutex.unlock();
return -1;
}
break;
}
mutex.unlock();
return retVal;
}
使用QMutexLocker:
int complexFunction(int flag)
{
QMutexLocker locker(&mutex);
int retVal = 0;
switch (flag) {
case 0:
case 1:
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0)
return -2;
retVal = status + flag;
}
break;
default:
if (flag > 10)
return -1;
break;
}
return retVal;
}
当然,使用QMutexLocker时,也需要注意QMutexLocker对象的生存周期,否则可能会出现锁时间过长,或者锁住的资源过多。
4.3、QReadLocker、QWriteLocker、QReadWriteLocker
还有一种场景,我们所保护的资源是具有读写权限的,多个线程可以同时读取某个资源,但是当存在写操作,写操作未完成时,就不允许其他线程对该资源进行读操作。
|
QReadWriteLock ( RecursionMode recursionMode ) |
|
|
void |
lockForRead () |
|
void |
lockForWrite () |
|
bool |
|
|
bool |
tryLockForRead ( int timeout ) |
|
bool |
|
|
bool |
tryLockForWrite ( int timeout ) |
|
void |
unlock () |
|
QReadLocker ( QReadWriteLock * lock ) |
|
|
~QReadLocker () |
|
|
QReadWriteLock * |
readWriteLock () const |
|
void |
relock () |
|
void |
unlock () |
|
QWriteLocker ( QReadWriteLock * lock ) |
|
|
QReadWriteLock * |
readWriteLock () const |
|
void |
relock () |
|
void |
unlock () |
实例:
QReadWriteLock lock;
void ReaderThread::run()
{
...
lock.lockForRead();
read_file();
lock.unlock();
...
}
void WriterThread::run()
{
...
lock.lockForWrite();
write_file();
lock.unlock();
...
}
4.4、QSemaphore
和QMutex不同的是,QSemaphore一次可以对多个资源进行保护,
例如以下场景:
某工厂只有固定仓位,生产人员每天生产的产品数量不一,销售人员每天销售的产品数量也不一致。当生产人员生产P个产品时,就一次需要P个仓位,当销售人员销售C个产品时,就要求仓库中有足够多的产品才能销售。
如果剩余仓位没有P个时,该批次的产品都不存入,当当前已有的产品没有C个时,就不能销售C个以上的产品,直到新产品加入后方可销售。
这就是典型的生产者-消费者问题。
|
QSemaphore ( int n = 0 ) |
|
|
~QSemaphore () |
|
|
void |
acquire ( int n = 1 ) |
|
int |
available () const |
|
void |
release ( int n = 1 ) |
|
bool |
tryAcquire ( int n = 1 ) |
|
bool |
tryAcquire ( int n, int timeout ) |
实例:
QSemaphore sem(5); // sem.available() == 5 默认有5个产品
sem.acquire(3); // sem.available() == 2 销售3个产品,成功
sem.acquire(2); // sem.available() == 0 销售2个产品成功
sem.release(5); // sem.available() == 5 生产5个产品
sem.release(5); // sem.available() == 10 生产10个产品
sem.tryAcquire(1); // sem.available() == 9, returns true 消费1个产品,成功
sem.tryAcquire(250); // sem.available() == 9, returns false 企图销售250个产品,失败,因为当前只剩下14个产品
4.5、QWaitCondition
QT线程(二)---线程同步的更多相关文章
- C#中的线程(二) 线程同步基础
1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具: 简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程 ...
- 第二十篇 .NET高级技术之C#中的线程(二) 线程同步基础
1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具: 简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程 ...
- MFC线程(二):线程同步临界区CRITICAL SECTION
当多个线程同时使用相同的资源时,由于是并发执行,不能保证先后顺序.所以假如时一个公共变量被几个线程同时使用会造成该变量值的混乱. 下面来举个简单例子. 假如有一个字符数组变量 char g_charA ...
- 【Qt开发】事件循环与线程 二
事件循环与线程 二 Qt 线程类 Qt对线程的支持已经有很多年了(发布于2000年九月22日的Qt2.2引入了QThread类),Qt 4.0版本的release则对其所有所支持平台默认地是对多线程支 ...
- 【转】Qt事件循环与线程 二
转自:http://blog.csdn.net/changsheng230/article/details/6153449 续上文:http://blog.csdn.net/changsheng230 ...
- Java线程:线程的同步与锁
一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public ...
- C#中的线程二(Cotrol.BeginInvoke和Control.Invoke)
C#中的线程二(Cotrol.BeginInvoke和Control.Invoke) 原文地址:http://www.cnblogs.com/whssunboy/archive/2007/06/07/ ...
- Qt学习笔记 线程(一)
Qt中的线程是与平台无关的 QThread 提供了创建一个新线程的方法 新建一个线程,继承QThread并重写它的run()当调用 start()函数时会调用重载的run()函数 例: #ifndef ...
- 基础学习day11--多线程一线程的创建,运行,同步和锁
一.线程基本概述 1.1.进程和线程 进程:一个应用程序一般都是一个进程,正在进行的程序 每一个进程最少都有一个线程,都有一个执行顺序,该顺序是一个执行路径或者一个控制单元 线程:进程中一个独立的控制 ...
- (转)Java线程:线程的同步与锁
Java线程:线程的同步与锁 一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Fo ...
随机推荐
- 中文乱码的分析 和 从Eclipse设置启动JVM时的字符集(转)
最近时常碰到中文乱码的问题,eclipse的编码环境设置的都是UTF-8,外部也是以UTF-8的编码进行传参的,但是遇到中文的时候还是因为乱码而产生一系列的错误.在网上查了许多资料,发现这是跟JVM的 ...
- C++和java的区别
Java区别于C++ 表面看来两者最大的不同在于Java没有指针,或者说,Java满地都是指针.对于编程者而言Java的这种设计是安全且更易用的.说Java满地是指针的原因在于它把指针的功能隐藏了,其 ...
- EJB理解
1. 我们不禁要问,什么是"服务集群"?什么是"企业级开发"? 既然说了EJB 是为了"服务集群"和"企业级开发",那么 ...
- 普通pc电脑安装苹果系统mac_详细教程(精)附带所有工具下载
苹果操作系统只允许在苹果电脑上面安装和使用.和Windows不一样,要在PC上安装,需要一系列的模拟和破解.破解安装的过程很繁琐而具有挑战性,以下是安装10A432雪豹的PC安装指南,附带25张图片帮 ...
- 【转】Cannot find -ltinfo when compiling android 4.0.3
原文网址:http://stackoverflow.com/questions/9055005/cannot-find-ltinfo-when-compiling-android-4-0-3 up v ...
- 为SharePoint网站创建自定义导航菜单
转:http://kaneboy.blog.51cto.com/1308893/397779 相信不少人都希望把SharePoint网站内置的那个顶部导航菜单,换成自己希望的样式.由于SharePoi ...
- C# asp.net 操作Word的前提配置和简单的方法
操作的前提: 1.要保证机器本身要安装OFFICE. 有时安装了Office,但是不能找到Microsoft Word 11.0(或者更高的版本) Object Library.那可能是因为在安装of ...
- Paxos算法(转)
Paxos算法的难理解与算法的知名度一样令人敬仰,从我个人的经历而言,难理解的原因并不是该算法高深到大家智商不够,而在于Lamport在表达该算法时过于晦涩且缺乏一个完整的应用场景.如果大师能换种思路 ...
- C# 深复制
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...
- MVVM中轻松实现Command绑定(三)任意事件的Command
WPF中不是所有的控件都有Command属性的,如果窗体我需要在ViewModel中处理Loaded事件命令,或者其他事件的命令时,很难都过绑定Command完成,必须要注册依赖属性或事件等,太麻烦了 ...