Qt多线程编程总结(二)——QMutex
QMutex类提供的是线程之间的访问顺序化。
QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。(在Java术语中,它和同步关键字“synchronized”很相似)。例如,这里有一个方法打印给用户两条消息:
- void someMethod()
- {
- qDebug("Hello");
- qDebug("World");
- }
如果同时在两个线程中调用这个方法,结果的顺序将是:
Hello
Hello
World
World
如果你使用了一个互斥量:
- QMutex mutex;
- void someMethod()
- {
- mutex.lock();
- qDebug("Hello");
- qDebug("World");
- mutex.unlock();
- }
用Java的术语,这段代码应该是:
- void someMethod()
- {
- synchronized {
- qDebug("Hello");
- qDebug("World");
- }
- }
然后同一时间只有一个线程可以运行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"); //当是自身时,直接返回false
- return 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 else
- d->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."的运行错误。
http://blog.csdn.net/mznewfacer/article/details/6966752
Qt多线程编程总结(二)——QMutex的更多相关文章
- Qt多线程编程总结(一)(所有GUI对象都是线程不安全的)
Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法. 这个文档是提供给那些对多线程编程有丰富的知识和经验的听众的.推荐阅 ...
- Qt多线程编程中的对象线程与函数执行线程
近来用Qt编写一段多线程的TcpSocket通信程序,被其中Qt中报的几个warning搞晕了,一会儿是说“Cannot create children for a parent that is in ...
- Web Worker javascript多线程编程(二)
Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...
- Java多线程编程(二)
在 Java多线程编程(一) 中的多线程并没有返回值,本文将介绍带返回值的多线程. 要想有返回值,则需要实现新的接口Callable而不再是Runnable接口,实现的方法也改为call()方法,执行 ...
- 多线程编程之二 ---MFC中的多线程开发
下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...
- Java多线程编程核心技术(二)对象及变量的并发访问
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
- c++多线程编程(二)
这是道面试题目:有三个线程分别打印A.B.C,请用多线程编程实现,在屏幕上循环打印10次ABCABC… 见代码: #include <iostream> #include <Wind ...
- Qt -------- 多线程编程
一.继承QThread(不推荐) 定义一个类,继承QThread,重写run(),当调用方法start(),启动一个线程,run()函数运行结束,线程结束. 二.继承QRunnable Qrunnab ...
- Java多线程编程(二)对象及变量的并发访问
一.synchronized同步方法 1.方法内的变量为线程安全 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了. 示例: ...
随机推荐
- JavaScript引用类型之Array数组的拼接方法-concat()和截取方法-slice()
1.concat() 基于当前数组中的所有项创建一个新数组(也就是副本),然后将接收到的参数添加到副本的末尾,最后返回新构建的数组.也就是说,concat()在向数组中追加元素时,不会改变原有数组 ...
- Activity中异步操作showDialog异常解决方法:判断Ay是否结束
Android – Displaying Dialogs From Background Threads 判断一下Activity是否在finishing就好了,否则万一Activity销毁了,这个D ...
- 从UIImage的矩阵变换看矩阵运算的原理
1.矩阵的基本知识: struct CGAffineTransform { CGFloat a, b, c, d; CGFloat tx, ty;}; CGAffineTransform CGAf ...
- C#实现文件批量重命名源码下载
本文要实现的功能是 文件批量重命名,当选择一个文件夹时,通过操作可以把文件夹下面所有文件进行重命名.建立了HoverTreeBatch项目. 然后 定义文件夹信息: DirectoryInfo _Th ...
- hadoop搭建杂记:Linux下hostname的更改办法
VirtualBox搭建hadoop伪分布式模式:更改hostname VirtualBox搭建hadoop伪分布式模式:更改hostname master: ip:192.168.56.120 机器 ...
- javascript函数apply和call
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性. Function.apply(obj,args)方法能接收两个参数obj:这个对象将代替Function类里this对象args:这 ...
- python 利用位移法将ip转为number以及将number转为ip
简介: 使用位移法将ip转为number型以及将number型转为ip,使用语言为python2.7 #!/usr/bin/env python # coding:utf-8 def ip2num(i ...
- mysql 特殊语句
1.获取下当前mysql的插件目录select @@plugin_dir 2.mysql移动文件 select load_file('文件路径') into dumpfile '导出路径' 3.des ...
- PHP上传图片
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- SSE && WebSockets
SSE && WebSockets 参考 http://www.bitscn.com/school/HTMLCSS/201402/194940.html WebSockets 定义了一 ...