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

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

  1. void someMethod()
  2. {
  3. qDebug("Hello");
  4. qDebug("World");
  5. }

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

  Hello
Hello
World
World

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

  1. QMutex mutex;
  2. void someMethod()
  3. {
  4. mutex.lock();
  5. qDebug("Hello");
  6. qDebug("World");
  7. mutex.unlock();
  8. }

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

  1. void someMethod()
  2. {
  3. synchronized {
  4. qDebug("Hello");
  5. qDebug("World");
  6. }
  7. }

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

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

实验部分:

情形一:

  1. #include <QtCore/QCoreApplication>
  2. #include <Qthread>
  3. #include <QTextStream>
  4. class MyThreadA : public QThread {
  5. public:
  6. virtual void run();
  7. };
  8. class MyThreadB: public QThread {
  9. public:
  10. virtual void run();
  11. };
  12. int number=6;
  13. void MyThreadA::run(){
  14. number *= 5;
  15. number /= 4;
  16. }
  17. void MyThreadB::run(){
  18. number *= 3;
  19. number /= 2;
  20. }
  21. int main(int argc, char *argv[])
  22. {
  23. QCoreApplication app(argc, argv);
  24. MyThreadA a;
  25. MyThreadB b;
  26. a.run();
  27. b.run();
  28. a.terminate();
  29. b.terminate();
  30. QTextStream out(stdout);
  31. out<<number;
  32. return app.exec();
  33. }

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

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

情形二:

  1. #include <QtCore/QCoreApplication>
  2. #include <Qthread>
  3. #include <QTextStream>
  4. class MyThreadA : public QThread {
  5. public:
  6. virtual void run();
  7. };
  8. class MyThreadB: public QThread {
  9. public:
  10. virtual void run();
  11. };
  12. int number=6;
  13. void MyThreadA::run(){
  14. number *= 5;
  15. sleep(1);
  16. number /= 4;
  17. }
  18. void MyThreadB::run(){
  19. number *= 3;
  20. sleep(1);
  21. number /= 2;
  22. }
  23. int main(int argc, char *argv[])
  24. {
  25. QCoreApplication app(argc, argv);
  26. MyThreadA a;
  27. MyThreadB b;
  28. a.start();
  29. b.start();
  30. a.wait();
  31. b.wait();
  32. QTextStream out(stdout);
  33. out<<number;
  34. return app.exec();
  35. }

运行结果:

number=11;

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

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

  1. bool QThread::wait(unsigned long time)
  2. {
  3. Q_D(QThread);
  4. QMutexLocker locker(&d->mutex);
  5. if (d->id == GetCurrentThreadId()) {
  6. qWarning("QThread::wait: Thread tried to wait on itself");     //当是自身时,直接返回false
  7. return false;
  8. }
  9. if (d->finished || !d->running) //与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值。
  10. return true;
  11. ++d->waiters;
  12. locker.mutex()->unlock();
  13. bool ret = false;
  14. switch (WaitForSingleObject(d->handle, time)) {   //调用win的对象处理函数
  15. case WAIT_OBJECT_0:    //核心对象被激活,等待成功
  16. ret = true;
  17. break;
  18. case WAIT_FAILED:
  19. qErrnoWarning("QThread::wait: Thread wait failure");
  20. break;
  21. case WAIT_ABANDONED:
  22. case WAIT_TIMEOUT:
  23. default:
  24. break;
  25. }
  26. locker.mutex()->lock();
  27. --d->waiters;
  28. if (ret && !d->finished) {                                  //虽然响应成功,但关联对象未结束执行
  29. // thread was terminated by someone else
  30. d->terminated = true;
  31. QThreadPrivate::finish(this, false);
  32. }
  33. if (d->finished && !d->waiters) {    //关联对象执行结束,并且等待数为零时,关闭句柄。
  34. CloseHandle(d->handle);
  35. d->handle = 0;
  36. }
  37. return ret;
  38. }

情形三:(Mutex 作用)

  1. #include <QtCore/QCoreApplication>
  2. #include <Qthread>
  3. #include <QTextStream>
  4. #include <QMutex>
  5. class MyThreadA : public QThread {
  6. public:
  7. virtual void run();
  8. };
  9. class MyThreadB: public QThread {
  10. public:
  11. virtual void run();
  12. };
  13. QMutex mutex;
  14. int number=6;
  15. void MyThreadA::run(){
  16. mutex.lock();
  17. number *= 5;
  18. sleep(1);
  19. number /= 4;
  20. mutex.unlock();
  21. }
  22. void MyThreadB::run(){
  23. mutex.lock();
  24. number *= 3;
  25. sleep(1);
  26. number /= 2;
  27. mutex.unlock();
  28. }
  29. int main(int argc, char *argv[])
  30. {
  31. QCoreApplication app(argc, argv);
  32. MyThreadA a;
  33. MyThreadB b;
  34. a.start();
  35. b.start();
  36. a.wait();
  37. b.wait();
  38. QTextStream out(stdout);
  39. out<<number;
  40. return app.exec();
  41. }

运行结果:

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的更多相关文章

  1. Qt多线程编程总结(一)(所有GUI对象都是线程不安全的)

    Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法. 这个文档是提供给那些对多线程编程有丰富的知识和经验的听众的.推荐阅 ...

  2. Qt多线程编程中的对象线程与函数执行线程

    近来用Qt编写一段多线程的TcpSocket通信程序,被其中Qt中报的几个warning搞晕了,一会儿是说“Cannot create children for a parent that is in ...

  3. Web Worker javascript多线程编程(二)

    Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...

  4. Java多线程编程(二)

    在 Java多线程编程(一) 中的多线程并没有返回值,本文将介绍带返回值的多线程. 要想有返回值,则需要实现新的接口Callable而不再是Runnable接口,实现的方法也改为call()方法,执行 ...

  5. 多线程编程之二 ---MFC中的多线程开发

    下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...

  6. Java多线程编程核心技术(二)对象及变量的并发访问

    本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...

  7. c++多线程编程(二)

    这是道面试题目:有三个线程分别打印A.B.C,请用多线程编程实现,在屏幕上循环打印10次ABCABC… 见代码: #include <iostream> #include <Wind ...

  8. Qt -------- 多线程编程

    一.继承QThread(不推荐) 定义一个类,继承QThread,重写run(),当调用方法start(),启动一个线程,run()函数运行结束,线程结束. 二.继承QRunnable Qrunnab ...

  9. Java多线程编程(二)对象及变量的并发访问

    一.synchronized同步方法 1.方法内的变量为线程安全 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了. 示例: ...

随机推荐

  1. 权威指南学习心得-浏览器中的js

    window对象:表示web了浏览器的一个窗口或窗体(winow属性引用自身) 含有以下属性:location包含Location对象,指定当前显示在窗口中URL,允许脚本往窗口里载入新的URL 含有 ...

  2. HTML5增加的几个新的标签

    HTML5又2008年诞生,HTML5大致可以等同于=html+css3+javascriptapi.... so --->支持css3强大的选择器和动画以及javascript的新的函数 先来 ...

  3. hive j简单邮件过滤

    select min(call_log), a.mail_subject from (select mail_to,mail_subject from dw_user_deviler_201408 w ...

  4. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  5. [C#技术参考]Socket传输结构数据

    最近在做一个机器人项目,要实时的接收机器人传回的坐标信息,并在客户端显示当前的地图和机器人的位置.当然坐标的回传是用的Socket,用的是C++的结构体表示的坐标信息.但是C#不能像C++那样很eas ...

  6. JS笔记 入门第四

    小测试: 注意:取消所有的设定可以直接使用 document.getElementById("txt").removeAttribute("style"); 这 ...

  7. 面试常用算法——Longest Palindromic Substring(最长回文子串)

    第一种: public static void main(String[] args) { String s = "abcbaaaaabcdcba"; int n,m; Strin ...

  8. Eclipse中搭建Python开发环境

    转载:http://www.cnblogs.com/realh/archive/2010/10/04/1841907.html Eclipse+PyDev环境搭建 1.准备工作 JDK6 Java 开 ...

  9. PADS Layout怎样放置间距一样的同一种元件

    少数元件的话,栅格设置是最好的,即将栅格设置成你要放置元件的间距,然后逐个移动元件放置.如果元件几十上百个,这样做就累死人了,此时就得设置阵列.按顺序选择你要放置的元件-右键-create arry, ...

  10. Module中引用Module中的Activity时报错了,错误是找不到R文件中的id引用

    1.好像库modul和主modul不能有相同名字和layout文件 2.资源文件名冲突导致的