QMutex类提供的是线程之间的访问顺序化。

QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。(在Java术语中,它和同步关键字“synchronized”很相似),(在Objective-C术语中,它和同步关键字“dispatch_sync”很相似)。例如,这里有一个方法打印给用户两条消息:

void someMethod()
{qDebug("Hello");qDebug("World");
}

如果同时在两个线程中调用这个方法,结果的顺序将是:

  HelloHelloWorldWorld

如果你使用了一个互斥量:

QMutex mutex;void someMethod()
{mutex.lock();qDebug("Hello");qDebug("World");mutex.unlock();}

用Java的术语,这段代码应该是:

void someMethod()
{synchronized {qDebug("Hello");qDebug("World");}
}

用Objective-C的术语,这段代码应该是:

 // 串行队列+同步任务
- (void)serialSyn{dispatch_queue_t queue =dispatch_queue_create("serial",DISPATCH_QUEUE_SERIAL);dispatch_sync(queue, ^{NSLog(@"hello");NSLog(@"word");});});

然后同一时间只有一个线程可以运行someMethod并且消息的顺序也一直是正确的。当然,这只是一个很简单的例子,但是它适用于任何需要按特定频率发生的情况。

但你在一个线程中调用lock(),其它线程将会在同一地点试图调用lock()来阻塞,知道这个线程调用unlock()之后其它线程才会获得这个锁。lock()的一种非阻塞选择是tryLock()。

实验部分:

情形一:

#include <QtCore/QCoreApplication>
#include <Qthread>
#include <QTextStream>class MyThreadA : public QThread {
public:virtual void run();
};class MyThreadB: public QThread {
public:virtual void run();
};
int number=6;
void MyThreadA::run(){number *= 5;number /= 4;
}
void MyThreadB::run(){number *= 3;number /= 2;
}
int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);MyThreadA a;MyThreadB b;a.run();b.run();a.terminate();b.terminate();QTextStream out(stdout);out<<number;return app.exec();}

上述代码,很简单,写了两个线程,覆盖了QThread的纯虚函数run(),这两个重构的run方法都是对全局变量number的操作,

主函数中顺序调用这两个方法,a.run()执行后number为7,b.run()执行后为10。

情形二:

#include <QtCore/QCoreApplication>#include <Qthread>#include <QTextStream>class MyThreadA : public QThread {public:virtual void run();};class MyThreadB: public QThread {public:virtual void run();};int number=6;void MyThreadA::run(){number *= 5;sleep(1);number /= 4;}void MyThreadB::run(){number *= 3;sleep(1);number /= 2;}int main(int argc, char *argv[]){QCoreApplication app(argc, argv);MyThreadA a;MyThreadB b;a.start();b.start();a.wait();b.wait();QTextStream out(stdout);out<<number;return app.exec();}

运行结果:

number=11;

利用QThread的方法start()同是开启两个线程,值得注意的是wait()函数,不能等待自己,这个是用来多个线程交互的,所以不能当sleep()用。这个函数是在主线程中被调用的时候阻塞了主线程。如果想在外部让子线程暂停,最好的办法是在子线程中设置一个标志,在主线程中更改这个标志,并在子线程的run函数中判断,通过调用其保护函数sleep()来达到暂停的目的了。

查看源代码,即可有清楚的概念:

bool QThread::wait(unsigned long time){Q_D(QThread);QMutexLocker locker(&d->mutex);if (d->id == GetCurrentThreadId()) {qWarning("QThread::wait: Thread tried to wait on itself"); //当是自身时,直接返回falsereturn false;}if (d->finished || !d->running) //与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值。return true;++d->waiters;locker.mutex()->unlock();bool ret = false;switch (WaitForSingleObject(d->handle, time)) { //调用win的对象处理函数case WAIT_OBJECT_0: //核心对象被激活,等待成功ret = true;break;case WAIT_FAILED:qErrnoWarning("QThread::wait: Thread wait failure");break;case WAIT_ABANDONED:case WAIT_TIMEOUT:default:break;}locker.mutex()->lock();--d->waiters;if (ret && !d->finished) { //虽然响应成功,但关联对象未结束执行// thread was terminated by someone elsed->terminated = true;QThreadPrivate::finish(this, false);}if (d->finished && !d->waiters) { //关联对象执行结束,并且等待数为零时,关闭句柄。CloseHandle(d->handle);d->handle = 0;}return ret;}

情形三:(Mutex 作用)

#include <QtCore/QCoreApplication>#include <Qthread>#include <QTextStream>#include <QMutex>class MyThreadA : public QThread {public:virtual void run();};class MyThreadB: public QThread {public:virtual void run();};QMutex mutex;int number=6;void MyThreadA::run(){mutex.lock();number *= 5;sleep(1);number /= 4;mutex.unlock();}void MyThreadB::run(){mutex.lock();number *= 3;sleep(1);number /= 2;mutex.unlock();}int main(int argc, char *argv[]){QCoreApplication app(argc, argv);MyThreadA a;MyThreadB b;a.start();b.start();a.wait();b.wait();QTextStream out(stdout);out<<number;return app.exec();}

运行结果:

number=10;

通过实验结果可以看出,QMutex保护了全局变量,同一时间只有一个线程可以访问它。

只得一提的是tryLock()的使用,若以上代码换为mutex.tryLock();那么执行结果可能为11,因为是试图锁定互斥量。如果锁被得到,这个函数返回真。如果另一个进程已经锁定了这个互斥量,这个函数返回假,而不是一直等到这个锁可用为止。

且不能添上sleep()函数,否则提示 "A mutex must be unlocked in the same thread that locked it."的运行错误。

Qt多线程之QMutex相关推荐

  1. QT多线程之:moveToThread

    不能在另外的线程直接delete一个QObject对象,相反,你需要调用QObject::deleteLater()函数,这个函数会给对象所在线程发送一个删除的事件. QObject的线程依附性是可以 ...

  2. Android多线程之ArrayBlockingQueue源码解析

    阻塞队列系列 Android多线程之LinkedBlockingQueue源码解析 Android多线程之SynchronousQueue源码解析 Andorid多线程之DelayQueue源码分析 ...

  3. Asp.Net Core 轻松学-多线程之Task快速上手

    Asp.Net Core 轻松学-多线程之Task快速上手 原文:Asp.Net Core 轻松学-多线程之Task快速上手 前言     Task是从 .NET Framework 4 开始引入的一 ...

  4. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  5. linux 线程pthread_detach,linux线程之pthread_join和pthread_detach

    在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...

  6. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

  7. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  8. Java多线程之CAS缺点

    Java多线程之CAS缺点 目录: 循环时间开销很大 只能保证一个共享变量的原子操作 引来ABA问题及解决方案(重点) 1. 循环时间开销很大 通过看源码,我们发现有个do while,如果CAS失败 ...

  9. Java多线程之CAS深入解析

    Java多线程之CAS深入解析 目录: CAS是什么 CAS底层原理Unsafe深入解析 CAS缺点 引子:蚂蚁花呗一面:讲一讲AtomicInteger,为什么要用CAS而不是synchronize ...

最新文章

  1. java事务设计iofo,Spring事务最佳实践
  2. 南农Nature Microbiology一作顾少华:我与铁载体的这5年
  3. 127.0.0.1和0.0.0.0和localhost的区别
  4. golang runtime.systemstack 泄漏排查
  5. 基于HTML5的WebGL结合Box2DJS物理引擎应用
  6. @Aspect注解无效
  7. Golang Context包的使用
  8. (十七)linux网络命令 vconfig ifconfig
  9. html把div分成两栏,div+css制作上中下,中间两列的全屏自适应布局
  10. win8改win7 教程
  11. [html] 用一个div模拟textarea的实现
  12. amqp协议 面试_分布式消息中间件-RabbitMQ面试题(必问)
  13. 修改marathon源码后,如何编译,部署到集群中?
  14. 阿里云存储:做深基础,助力新基建 | 凌云时刻
  15. 解放双手,CSDN博客支持公众号自动同步!
  16. 全国计算机考试照片传不上去,成人高考报名照片传不上去怎么办
  17. 设置WebView字体颜色,背景颜色
  18. 交通信号灯课程设计(红绿灯)
  19. 华为CE系列和S系列交换机堆叠配置及mad检测
  20. 立象Argox OX- 100条码机如何打印标签

热门文章

  1. java web 路径 .html,java web 路径(java web 路径).doc
  2. 轨迹分析_解析几何中的轨迹问题中经典问题,有详细分析及其解答
  3. 如何做一份能忽悠投资人的PPT
  4. python跳一跳编程构造_python实现微信跳一跳辅助工具步骤详解
  5. System Verilog 线程间的通信——事件,信箱与旗语
  6. 局域网中用centos6架设ftp服务器-配置文件说明
  7. 用泛型的sort与binarySearch方法
  8. java注解获取参数_JAVA 自定义注解及参数获取 | 学步园
  9. html二维坐标系转换,旋转坐标系 转换工具
  10. linux新建两个工作组,linux添加工作组