本文共 2363 字,大约阅读时间需要 7 分钟。
http://blog.csdn.net/gulansheng/article/details/44851727
Youtube上有一个很出名的Qt视频教程,讲得简练精要。但是在他讲到的Qt线程同步一集的时候,我凭着自己的经验,感觉他讲得是错的。于是在网上大范围的搜索“qt线程同步”这个关键字,试图找到一些线索,以证明视频教程中的错误。但是看了很多个博客之后,我发现大家都是千篇一律,很是吃惊。真是误导大家。所以特意写这篇文章来证实一下。
首先我们要知道为什么要用线程同步?那是因为在多线程编程里面,会有一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。 在这里我们引用一个网上较为流行的一个例子。如下所示,这是一个线程的实现:class Thread : public QThread { public: Thread(); void stop(); protected: virtual void run(); private: bool m_stop; }; Thread::Thread() { m_stop = false; } void Thread::stop() { m_stop = true; } void Thread::run() { while (!m_stop) { sleep(1); qDebug("vic.MINg!"); } qDebug("end!"); }
Qt中的线程是以对象的形式存在的。如果我们在main函数中生成几个此类的线程对象,如下:
Thread m1; Thread m2; Thread m3; m1.start(); m2.start(); m3.start();
那么m1,m2,m3之间会有我们自己定义的共享数据存在吗?显然,从C++对象的概念出发来理解,他们之间是不会存在这些共享数据的。因为各个对象会维护各自对象空间里的变量。按上面例子中的代码来看,m1,m2,m3分别有着一个自己的m_stop,那我们还有必要对这个m_stop来做同步操作吗?显然是没有必要的。而网上的多数例子,以及那个Youtube的视频却对m_stop做了同步操作,引用原文的代码:
//thread.h头文件,添加互斥量对象 private: ... QMutex mutex; }; void Thread::run() { forever { mutex.lock(); if (m_stop) { m_stop = false; mutex.unlock(); break; } mutex.unlock(); qDebug("vic.MINg!"); } qDebug("end!"); } void Thread::stop() { mutex.lock(); m_stop = true; mutex.unlock(); }
文中的意思是使用QMutex保护上面的线程类的m_stop布尔变量,我们就纳闷了,一个不被多个线程共享的数据还需要被保护呢?其中一个线程对象把这个变量改变了,其他线程对象的这个变量又不会受到什么影响。这样做又有什么意义可言。
且不争论这个,这还不算最大的问题所在。最大的问题是定义的互斥变量也是作为类的成员变量来定义的。那么由这个线程类生成m1,m2,m3对象势必是三个不相干的互斥量,你怎么可能因为把m1的互斥量上锁,而不能让m2对自己的互斥量上锁呢?也就是说,这三个线程压根不是被同一个互斥量来协调,以达到同步的。因此,网上的多数Qt多线程同步的例子可以说是错误的。 线程同步,首先你必须保证多个线程受控于共有的一个互斥量,我们想达到共有一个互斥量需要将互斥量定义为静态变量才对。如下所示:class Thread : public QThread{public: Thread(); ~Thread();private: void run();public: QString name; static QMutex m;//只有这种情况下,互斥量才是被所有此类线程所共享的};//这一句最好定义在对应的cpp文件中,避免重复定义QMutex MyThread::m; //静态对象必须定义
由C++对象的特征我们可以知道,以上的QMutex对象在所有的此类线程中是共享的,通过这样去修改,才真正地多个线程同步。为了避免大家被网上错误的讲解所误解,免得把多线程同步按照他们的方式去写,特发此文。
如果哪里有不对,请大家给我指出,我将不胜感激!! 我把随便参考的一个错误链接贴出来: Youtube视频链接: