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 ...
随机推荐
- 133. Clone Graph
题目: Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. ...
- 如何将Springside4项目转成Eclipse项目
1)下载springside4 官网地址 http://www.springside.org.cn/download.html 2)运行CMD,进入 C:\Documents and Settings ...
- is present but cannot be translated into a null value due to being declared as a primitive type
解决办法:把基本类型改为对象,譬如此处将pageId的类型由int 改为Integer 2016-10-19 19:36:11.275 DEBUG [http-nio-9999-exec-2][org ...
- 【HDOJ】5564 Clarke and digits
DP+快速矩阵幂.注意base矩阵的初始化,不难. /* 5564 */ #include <iostream> #include <string> #include < ...
- hadoop2.2原理:采样器
多输入路径-只采一个文件-(MultipleInputs+getsample(conf.getInputFormat) 之前弄采样器,以为已经结束了工作,结果现在又遇到了问题,因为我的输入有两个文件, ...
- PHP ‘scan’函数拒绝服务漏洞
漏洞名称: PHP ‘scan’函数拒绝服务漏洞 CNNVD编号: CNNVD-201311-464 发布时间: 2013-12-06 更新时间: 2013-12-06 危害等级: 中危 漏洞类型 ...
- Journal.Today 1.0.0
我喜欢把一天的日记都放在一个文件中,而不是每次都新建一个文件. 写了一个脚本,检测当天是否已经新建日记,已经新建则打开,未新建则新建并打开. 其中我不太喜欢Wiz日记本来的标题命名方式,所以都 ...
- HDU 2647
思路:拓扑排序 #include<stdio.h> #include<string.h> typedef struct { int to; int next; }EdgeNod ...
- Unity的Lerp函数实现缓动
在Unity里面Lerp函数可以实现缓动效果 下面例子实现点光源的移动 在场景中创建好一个平面,一个点光源,我在这里随便放了一个模型. 然后新建c#脚本,代码如下: using UnityEngine ...
- Ubuntu 14.04 SSH + 远程登录xrdp
1. 安装ssh 打开"终端窗口",输入"sudo apt-get install openssh-server"-->回车-->输入"y ...