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!");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
Qt中的线程是以对象的形式存在的。如果我们在main函数中生成几个此类的线程对象,如下:
Thread m1;
Thread m2;
Thread m3;
m1.start();
m2.start();
m3.start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
那么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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
文中的意思是使用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; //静态对象必须定义
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
由C++对象的特征我们可以知道,以上的QMutex对象在所有的此类线程中是共享的,通过这样去修改,才真正地多个线程同步。为了避免大家被网上错误的讲解所误解,免得把多线程同步按照他们的方式去写,特发此文。
如果哪里有不对,请大家给我指出,我将不胜感激!!
我把随便参考的一个错误链接贴出来:http://mobile.51cto.com/symbian-272643.htm
Youtube视频链接:http://www.youtube.com/playlist?list=PL2D1942A4688E9D63