你做錯了。。。

http://www.cnblogs.com/tankery/archive/2011/03/09/2004561.html


英文原文:http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

我們之間經常使用IRC(網絡聊天工具?)進行交流,社區也同樣是這樣。我在上 Freenode 網絡的 QT 頻道時會幫那些有問題的人解答。一個普遍的問題(也是我厭煩的問題)是如何理解QT多線程,還有如何使他們的代碼工作。他們將他們的代碼,或者基於他們代碼的實例展示給我看,而我經常會回覆他們一句:

你做錯了。。。

我知道這個回答是有些無禮的,甚至是有些諷刺的。但我不禁想到,下面的這個類(假想)是一個不正確的多線程原則的應用,也是不正確的QT運用。

class MyThread : public QThread
{
public:
    MyThread()
    {
        moveToThread(this);
    }
    void run();
signals:
    void progress(int);
    void dataReady(QByteArray);
public slots:
    void doWork();
    void timeoutHandler();
};

我最不能忍受的代碼是moveToThread(this); 我看到非常多的人在不理解這句話做了什麼的情況下使用它。它做了什麼?moveToThread函數讓QT確保事件句柄和擴展的信號和槽已經被指定的線程上下文調用,因爲QThread是一個線程接口,所以我們讓線程的代碼運行在“它自己裏面”,我們也會在線程運行之前做這樣的事。即使這樣似乎能工作,但它令人迷惑,而且這也不是QThread設計的使用方式(所有QThread的函數編寫時是希望在線程創建時被調用,而不是QThread類初始化時)。 我想,moveToThread(this);如此“恐怖的” (creeps) 寫入到人們的代碼中是因爲他們看到有些博客也這麼用。簡單的網絡搜索就會出現好幾篇這樣的博客,大家基本都是按照下面的方法做的:

  1. 繼承QThread
  2. 添加一些消息和槽來完成工作
  3. 測試代碼,發現那些槽並不是從“正確的線程”中調用的
  4. 問Google,找到moveToThread(this);方法,然後加了些註釋:“當我添加這個的時候它似乎工作得很好

在我看來,問題出在第一步。QThread 是被設計來作爲接口或者操作系統線程控制點(a control point to an operating system thread)使用的,不是一個放置你的多線程代碼的地方。我們面向對象程序員繼承一個類是爲了擴展或者特殊化(specialize )基類的方法。我想,繼承QThread的唯一正當的理由是添加QThread沒有的方法,例如,也許要提供一個內存指針來實現線程棧,或者可能是添加實時接口支持。一段下載文件,查詢數據庫,或者任何其他處理的代碼不應該繼承QThread。它應該獨立(encapsulated)在它自己的對象中。

通常,這意味着簡單的從QThread修改你的代碼到QObject,然後,可能需要修改你的類名。當你需要做些初始化時,你可以連接QThread的started信號。你需要實例化一個QThread並使用moveToThread(this);函數指派你的對象到此線程中,讓你的代碼真正運行在新的線程上下文中。即使你仍然是使用moveToThread函數讓QT在指定的線程上下文中運行你的代碼,但是我們保持了線程接口的獨立性。如果有必要,現在就可能是時候將你的類的多個實例指派到一個單獨的線程中,或者多個類的多個實例指派到一個單獨的線程中了,換句話說,每個線程綁定一個實例也許是不必要的。(可以減少不必要的線程創建,譯者注)

我常常埋怨那些混淆的線程相關的QT代碼的編寫。原始的QThread類是抽象的,所以繼承是必要的。直到QT4.4,QThread::run()實現了一個默認的定義。在這之前,使用QThread唯一的方法是繼承它。但是隨着線程相關的添加和不同類別的對象之間的信號和槽的連接,我們突然有了一個方便的線程使用方法。我們喜歡簡單,所以我們希望使用它。但不幸的是已經晚了。迫使人們繼承QThread已經使它變得比預想的更難以改變。 我也埋怨沒有一份最新的示例代碼或者文檔來告訴人們如何理由便捷的方法使他們從頭疼中解脫出來。到現在爲止,我發現的最好的資源是一篇我以前寫的博客

免責聲明:上面你看到的所有內容是顯而易見的觀點。我做了很多關於這些類的工作,我很清楚的知道如何來使用或者如何不使用它們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章