網上Qt多線程同步的一種普遍誤識

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對象在所有的此類線程中是共享的,通過這樣去修改,才真正地多個線程同步。爲了避免大家被網上錯誤的講解所誤解,免得把多線程同步按照他們的方式去寫,特發此文。
如果哪裏有不對,請大家給我指出,我將不勝感激!!
我把隨便參考的一個錯誤鏈接貼出來:http://mobile.51cto.com/symbian-272643.htm
Youtube視頻鏈接:http://www.youtube.com/playlist?list=PL2D1942A4688E9D63

發佈了29 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章