QT基礎五


18.1        Creaing Threads

      Qt中提供多線程的機制很簡單:創建QThread的派生類,並重新實現其保護成員函數run()。
     
      QThread::run(),被調用來開始線程的執行,在run()結束時線程終止。
     
      QThread::terminate(),用來終止線程的執行,非阻塞操作,並不保證線程的立即終止;可以在調用QThread::terminate()之后調用QThread::wait()來實現同步等待。
     
      terminate()並不是值得推薦結束線程的方法,因為它強制線程終止而不給線程任何清場的機會。
     
18.2        Synchronizing Threads

      Qt提供的用於線程同步的類包括QMutex,QReadWriteLock,QSemaphore和QWaitCondition
     
QMutex

      QMutex::lock()                    阻塞操作
      QMutex::trylock()              非阻塞操作
      QMutex::unlock()     
     
      QMutexLocker是Qt提供的用於簡化Mutex操作的一個類--QMutexLocker的構造函數以一個QMutex對象為參數,並對其自動執行lock操作;而在析構函數則對其自動執行unlock操作。
     
QReadWriteLock可以允許同時進行多個讀操作或一個寫操作。
     
      QReadWriteLock::lockForRead()
      QReadWriteLock::lockForWrite()
      QReadWriteLock::unlock()
     
QSemaphore是對Mutex的擴展;與讀寫鎖不同的是,信號量可以用來保護一批相同的資源,而不只是一個。
     
      QSemaphore::acquire(int n=1)
      QSemaphore::release(int n=1)
      QSemaphore::available()
     
QWaitCondition和QMutex聯合使用,可以允許一個線程在某個條件滿足時喚醒其他線程,比起單獨使用QMutex能實現更精確的控制。
     
      QWaitCondition::wait()的參數是一個狀態為locked的QMutex,該函數在阻塞本線程前會將這個QMutex解鎖,並在函數返回前對其lock。
     

TLS(thread-local storage)

      較好的實現方法是使用QThreadStorage< T> 類,該類常用來實現cache,這樣可以避免使用mutex時lock,unlock以及等待帶來的開銷。
     
      由於某些編譯器的問題,QThreadStorage< T> 中只能存放指針。

      QThreadStorage::hasLocalData()
      QThreadStorage::setLocalData()

     
18.3        Communicating with MainThread
     
      當Qt程序運行時,主線程是唯一的線程,並且是唯一允許創建QApplication或QCoreApplication對象並對其調用exec()的線程。在調用exec()之后,主線程要么是在等待event的發生,要么是在處理一個event。
     
      主線程可以通過創建QThread的子類來開始新線程。
     
      之前介紹的mutex,read/write lock,semaphore等均可用於新線程之間的通訊,但是卻不能用於和主線程的通訊,因為這會導致主循環的event loop被阻塞並" 凍結" UI。
     
      解決方案是在主線程與新線程之間跨線程的使用signal-slot機制。
     
      通常情況下signal-slot機制是同步工作的,這意味着當signal被emit時,與之想聯系的slot會被立即調用。
     
      然而,當該機制用於將不同線程中的object連接起來時,則變為異步機制。這樣的連接是在底層是通過創建並傳遞event來實現的;slot被signal的接收對象所在的線程的event loop所調用。
     
      默認情況下,一個QObject對象存在於其被創建的線程之中;這可以在任何時候調用QObject::moveToThread()被改變。
     

18.4        Using Qt's Classess in Secondary Threads

      Thread-safe & Reentrant        注意留意這兩個概念應用在函數和類之上的不同。
     
      對於類,如果它的所有成員函數都可以被不同線程同時調用而不相互影響--即使這些調用是針對同一個類對象,那么該類被定義為thread-safe。

      對於類,如果其不同實例可以在不同線程中被同時使用而不相互影響,那么該類被定義為reentrant;然而,不同線程中同時訪問同一個reentrant類對象,並不是安全的,這樣的訪問需要用mutex進行保護。
     
      在Qt的定義中,在類這個層次,thread-safe是比reentrant更嚴格的要求,這和在函數層次上的關系正好相反。
     
      通常情況下C++的類只要不使用全局或其它共享變量,就是reentrant的。

      Qt中大多數non-GUI的類,是屬於reentrant的。QObject是reentrant的,但是需要注意以下幾點:
     
      1).        子QObject必須在父QObject所屬的線程中被創建,這意味着在非主線程中的對象在創建時不允許以QThread作為parent,因為后者是在主線程或另外一個非主線程中被創建的。
      2).        在刪除一個QThread對象前,必須將對應線程中創建的所有對象都銷毀。
      3).        對象必須在其被創建的線程中被刪除。

        如果需要刪除存在於另一個線程中的對象,必須調用線程安全的QObject::deleteLater()函數,該函數會發送一個" defered delete" event。
       
        QWidget及其子類不是reentrant的。
       
     

 


Chapter 19 Creating Plugins


      Qt提供了Qlibrary類,用於以一種平台無關的方式實現在程序運行時加載共享庫。
     
19.1        Extending Qt with Plugins

      Qt本身可以被很多類型的plugin擴展,最常見的包括database drivers,image formats,text codecs等。
     
      對於每種類型的plugin,通常都需要兩個類:一個wrapper類實現該類通用的plugin API,以及一個或多個handler類,每個類實現一個plugin特定的API。
     
      在plugin的.cpp文件中,需要使用Q_EXPORT_PLUGIN()這個宏來確保plugin能夠被Qt識別。
     
      plugin真正執行的操作都是通過其handler類來實現的。
     
      plugin的.pro文件與應用程序不同。默認情況下.pro文件使用app模板,然而這里必須使用lib模板,因為plugin屬於庫,而不是一個獨立的應用程序。
           
      QCoreApplication::addLibraryPath( ),為程序添加新的庫路徑。

19.2        Making Application Plugin-Aware

      應用程序的plugin實際是實現了一個或多個接口(interface)的動態庫。應用程序與plugin之間的通訊是通過interface的virtual table來完成的。
     
      一個接口(interface)通常聲明一個virtual析構函數,一個返回QStringList的virtual函數,以及一個或多個其他virtual函數。
     
      在接口聲明的尾部,需要調用Q_DECLARE_INTREFACE2()來將該interface與某個標識符關聯起來。
     
      QPluginLoader類用於在運行時加載plugin。

      QPluginLoader::load(),通常不需要顯式調用,因為instance()函數會在必要時調用該函數完成加載。
      QPluginLoader::instance(),返回一個指向plugin對象的QObject *指針。
     
      同一個插件plugin可以成功cast至多個interface,因為plugin可以通過多重繼承來提供多個interface。

19.3        Writing Application Plugins

      應用程序的plugin是其要提供的interface和QObject二者的子類。
     
      在plugin的源代碼中,需要為其提供的每個Interface都要使用Q_INTERFACES()宏,來保證moc和qobject_cast< T> 之間的協調工作。
     
      在.cpp文件的尾部,同樣需要調用Q_EXPORT_PLUGIN2()宏來使該plugin對於Qt可用。
     

 

 

Chapter 20 Platform-Specific Features

 

20.1        Interfacing with Native APIs

      在每個平台上,Qt都為QWidget提供了一個winId()函數,返回window ID或是句柄;QWidget還提供了一個靜態函數find(),返回一個特定window ID對應的widget。我們可以將獲得的window ID傳遞給Native API來執行平台特定的操作。

      Qt定義了以下系統標志:Q_WS_WIN,Q_WS_X11,Q_WS_MAC,Q_WS_QWS(Qtopia)。
     
      QSysInfo::WindowsVersion  QSysInfo::MacintoshVersion      這兩個靜態變量存儲着WIN和MAC操作系統的版本信息
     
20.2        Using ActiveX on Windows

      ActiveX構建於Microst COM之上,它為使用組件的應用程序定義了一套接口,為提供組件的庫和應用程序定義了另一套接口。
     
      ActiveQt由兩個模塊組成:
     
              QAxContainer模塊允許用戶使用COM object並在Qt程序中內嵌ActiveX控件。

              QAxServer模塊允許用戶導出自定義的COM object以及用Qt編寫的ActiveX控件。
     
      Q_ENUMS()宏的作用是告知moc其" 宏參數" 是枚舉類型。
     

      QAxContainer模塊由三個類組成:QAXObject封裝一個COM object,QAxWidget封裝一個ActiveX控件,QAxBase為QAxObject和QAxWidget實現核心COM功能。
     
      QAxObject派生自QAxBase和QObject,QAxWidget派生自QAxBase和QWidget。
     
      COM中的數據類型會被自動轉換為合適的Qt數據類型。
           
      QAxBase::setControl()
     
      QObject::setProperty()可用於設置COM property和Qt property。
     
      要鏈接QAxContainer庫的話,需要在.pro文件中添加下列一行:" CONFIG +=qaxcontainer"
     
      QAxBase::dynamicCall()
     
      注意,QAxObject和QAxWidget的子類無法定義新的property,signal和slot。
     

      QAxServer模塊允許將一個標准Qt程序轉換為一個ActiveX server。該server可以是共享庫,也可以是獨立的應用程序。共享庫形式的server被稱為in-process servers,而獨立應用程序形式的server被稱為out-of-process server。
     
      QAxBindable在widget與ActiveX client之間提供了一個接口。
     
      在Qt中處理多重繼承中,如果基類中存在QObject的派生類,必須將這樣的類放在首位。
     
      QAXFACTORY_DEFAULT()宏的作用是導出一個AxtiveX控件,可以用於僅導出一個控件的ActiveX server;當server要導出多個控件時,不能使用QAXFACTORY_DEFAULT()宏。
     
      QApplication能夠識別命令行中的-activex參數,並使應用程序作為server而運行。
     
      Q_CLASSINFO()宏

     
20.3        Handling X11 Session Management

      為了使一個Qt/X11應用程序意識到session manager的存在,需要重新實現QApplication::saveState()函數,並在該函數中保存應用程序的狀態信息。
     
      當用戶啟動shutdown操作時,程序員可以通過重新實現QApplication::commitData()來獲取控制權,這允許應用程序保存未保存的數據,並且與用戶交互--如果可能的話;這部分session management在X11和Windows上都被支持。
     
      QObject::setObjectName()
     
      void QApplicatoin::saveState(QSessionManager &)--該函數在session manager希望應用程序保存其狀態時被調用,QSessionManager類型的參數允許應用程序與session manager進行通訊。
     
           
      discard command:是指session manager必須執行的用刪除任何存儲當前狀態信息的命令。
      restart command:是指session manager必須執行的用以重新啟動應用程序的命令。
     
      QSessionManager::setDiscardCommand(QStringList &)
      QSessionManager::setDiscardCommand(QStringList & )
     
      默認情況下,Qt提供的restart command的格式為: appname -session id_key
     
      QSessionManager::release()
      QSessionManager::cancel()
     
      QApplication:isSessionRestored()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM