黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

Qt中的多線(xiàn)程編程

系統(tǒng) 2022 0

Qt中的多線(xiàn)程編程

文檔選項(xiàng)

打印本頁(yè)

將此頁(yè)作為電子郵件發(fā)送

Qt 作為一種基于 C++ 的跨平臺(tái) GUI 系統(tǒng),能夠提供給用戶(hù)構(gòu)造圖形用戶(hù)界面的強(qiáng)大功能。為了滿(mǎn)足用戶(hù)構(gòu)造復(fù)雜圖形界面系統(tǒng)的需求,Qt 提供了豐富的多線(xiàn)程編程支持。

Qt 作為一種基于 C++ 的跨平臺(tái) GUI 系統(tǒng),能夠提供給用戶(hù)構(gòu)造圖形用戶(hù)界面的強(qiáng)大功能。為了滿(mǎn)足用戶(hù)構(gòu)造復(fù)雜圖形界面系統(tǒng)的需求,Qt 提供了豐富的多線(xiàn)程編程支持。從 2.2 版本開(kāi)始,Qt 主要從下面三個(gè)方面對(duì)多線(xiàn)程編程提供支持:一、構(gòu)造了一些基本的與平臺(tái)無(wú)關(guān)的線(xiàn)程類(lèi);二、提交用戶(hù)自定義事件的 Thread-safe 方式;三、多種線(xiàn)程間同步機(jī)制,如信號(hào)量,全局鎖。這些都給用戶(hù)提供了極大的方便。不過(guò),在某些情況下,使用定時(shí)器機(jī)制能夠比利用 Qt 本身的多線(xiàn)程機(jī)制更方便地實(shí)現(xiàn)所需要的功能,同時(shí)也避免了不安全的現(xiàn)象發(fā)生。本文不僅對(duì) Qt 中的多線(xiàn)程支持機(jī)制進(jìn)行了討論,還著重探討了利用定時(shí)器機(jī)制模擬多線(xiàn)程編程的方法。

1、系統(tǒng)對(duì)多線(xiàn)程編程的支持

不同的平臺(tái)對(duì) Qt 的多線(xiàn)程支持方式是不同的。當(dāng)用戶(hù)在 Windows 操作系統(tǒng)上安裝 Qt 系統(tǒng)時(shí),線(xiàn)程支持是編譯器的一個(gè)選項(xiàng),在 Qt 的 mkfiles 子目錄中包括了不同種類(lèi)編譯器的編譯文件,其中帶有 -mt 后綴的文件才是支持多線(xiàn)程的。

而在 Unix 操作系統(tǒng)中,線(xiàn)程的支持是通過(guò)在運(yùn)行 configure 腳本文件時(shí)添加 -thread 選項(xiàng)加入的。安裝過(guò)程將創(chuàng)建一個(gè)獨(dú)立的庫(kù),即 libqt-mt,因此要支持多線(xiàn)程編程時(shí),必須與該庫(kù)鏈接(鏈接選項(xiàng)為-lqt-mt),而不是與通常的 Qt 庫(kù)(-lqt)鏈接。

另外,無(wú)論是何種平臺(tái),在增加線(xiàn)程支持時(shí)都需要定義宏 QT_THREAD_SUPPORT(即增加編譯選項(xiàng)-DQT_THREAD_SUPPORT)。在 Windows 操作系統(tǒng)中,這一點(diǎn)通常是在 qconfig.h 文件中增加一個(gè)選項(xiàng)來(lái)實(shí)現(xiàn)的。而在 Unix 系統(tǒng)中通常添加在有關(guān)的 Makefile 文件中。





回頁(yè)首


2、Qt中的線(xiàn)程類(lèi)

在 Qt 系統(tǒng)中與線(xiàn)程相關(guān)的最重要的類(lèi)當(dāng)然是 QThread 類(lèi),該類(lèi)提供了創(chuàng)建一個(gè)新線(xiàn)程以及控制線(xiàn)程運(yùn)行的各種方法。線(xiàn)程是通過(guò) QThread::run() 重載函數(shù)開(kāi)始執(zhí)行的,這一點(diǎn)很象 Java 語(yǔ)言中的線(xiàn)程類(lèi)。在 Qt 系統(tǒng)中,始終運(yùn)行著一個(gè)GUI 主事件線(xiàn)程,這個(gè)主線(xiàn)程從窗口系統(tǒng)中獲取事件,并將它們分發(fā)到各個(gè)組件去處理。在 QThread 類(lèi)中還有一種從非主事件線(xiàn)程中將事件提交給一個(gè)對(duì)象的方法,也就是 QThread::postEvent()方法,該方法提供了 Qt 中的一種 Thread-safe 的事件提交過(guò)程。提交的事件被放進(jìn)一個(gè)隊(duì)列中,然后 GUI 主事件線(xiàn)程被喚醒并將此事件發(fā)給相應(yīng)的對(duì)象,這個(gè)過(guò)程與一般的窗口系統(tǒng)事件處理過(guò)程是一樣的。值得注意的是,當(dāng)事件處理過(guò)程被調(diào)用時(shí),是在主事件線(xiàn)程中被調(diào)用的,而不是在調(diào)用QThread::postEvent 方法的線(xiàn)程中被調(diào)用。比如用戶(hù)可以從一個(gè)線(xiàn)程中迫使另一個(gè)線(xiàn)程重畫(huà)指定區(qū)域:

                    QWidget *mywidget;
QThread::postEvent(mywidget, new QPaintEvent(QRect(0,0,100,100)));
                
                  

然而,只有一個(gè)線(xiàn)程類(lèi)是不夠的,為編寫(xiě)出支持多線(xiàn)程的程序,還需要實(shí)現(xiàn)兩個(gè)不同的線(xiàn)程對(duì)共有數(shù)據(jù)的互斥訪(fǎng)問(wèn),因此 Qt 還提供了 QMutex 類(lèi),一個(gè)線(xiàn)程在訪(fǎng)問(wèn)臨界數(shù)據(jù)時(shí),需要加鎖,此時(shí)其他線(xiàn)程是無(wú)法對(duì)該臨界數(shù)據(jù)同時(shí)加鎖的,直到前一個(gè)線(xiàn)程釋放該臨界數(shù)據(jù)。通過(guò)這種方式才能實(shí)現(xiàn)對(duì)臨界數(shù)據(jù)的原子操作。

除此之外,還需要一些機(jī)制使得處于等待狀態(tài)的線(xiàn)程在特定情況下被喚醒。QWaitCondition 類(lèi)就提供了這種功能。當(dāng)發(fā)生特定事件時(shí),QWaitCondition 將喚醒等待該事件的所有線(xiàn)程或者喚醒任意一個(gè)被選中的線(xiàn)程。





回頁(yè)首


3、用戶(hù)自定義事件在多線(xiàn)程編程中的應(yīng)用

在 Qt 系統(tǒng)中,定義了很多種類(lèi)的事件,如定時(shí)器事件、鼠標(biāo)移動(dòng)事件、鍵盤(pán)事件、窗口控件事件等。通常,事件都來(lái)自底層的窗口系統(tǒng),Qt 的主事件循環(huán)函數(shù)從系統(tǒng)的事件隊(duì)列中獲取這些事件,并將它們轉(zhuǎn)換為 QEvent,然后傳給相應(yīng)的 QObjects 對(duì)象。

除此之外,為了滿(mǎn)足用戶(hù)的需求,Qt 系統(tǒng)還提供了一個(gè) QCustomEvent 類(lèi),用于用戶(hù)自定義事件,這些自定義事件可以利用 QThread::postEvent() 或者QApplication::postEvent() 被發(fā)給各種控件或其他 QObject 實(shí)例,而 QWidget 類(lèi)的子類(lèi)可以通過(guò) QWidget::customEvent() 事件處理函數(shù)方便地接收到這些自定義的事件。需要注意的是:QCustomEvent 對(duì)象在創(chuàng)建時(shí)都帶有一個(gè)類(lèi)型標(biāo)識(shí) id 以定義事件類(lèi)型,為了避免與 Qt 系統(tǒng)定義的事件類(lèi)型沖突,該 id 值應(yīng)該大于枚舉類(lèi)型 QEvent::Type 中給出的 "User" 值。

在下面的例子中,顯示了多線(xiàn)程編程中如何利用用戶(hù)自定義事件類(lèi)。

UserEvent類(lèi)是用戶(hù)自定義的事件類(lèi),其事件標(biāo)識(shí)為346798,顯然不會(huì)與系統(tǒng)定義的事件類(lèi)型沖突。

                    class UserEvent : public QCustomEvent   //用戶(hù)自定義的事件類(lèi)
{
public:
 UserEvent(QString s) : QCustomEvent(346798), sz(s) { ; }
 QString str() const { return sz; }
private:
 QString sz;    
};
                
                  

UserThread類(lèi)是由QThread類(lèi)繼承而來(lái)的子類(lèi),在該類(lèi)中除了定義有關(guān)的變量和線(xiàn)程控制函數(shù)外,最主要的是定義線(xiàn)程的啟動(dòng)函數(shù)UserThread::run(),在該函數(shù)中創(chuàng)建了一個(gè)用戶(hù)自定義事件UserEvent,并利用QThread類(lèi)的postEvent函數(shù)提交該事件給相應(yīng)的接收對(duì)象。

                    class UserThread : public QThread      //用戶(hù)定義的線(xiàn)程類(lèi)
{
public:
 UserThread(QObject *r, QMutex *m, QWaitCondition *c);
QObject *receiver;
}
void UserThread::run()     //線(xiàn)程類(lèi)啟動(dòng)函數(shù),在該函數(shù)中創(chuàng)建了一個(gè)用戶(hù)自定義事件
{UserEvent *re = new UserEvent(resultstring);
   QThread::postEvent(receiver, re); 
}
                
                  

UserWidget類(lèi)是用戶(hù)定義的用于接收自定義事件的QWidget類(lèi)的子類(lèi),該類(lèi)利用slotGo()函數(shù)創(chuàng)建了一個(gè)新的線(xiàn)程recv(UserThread類(lèi)),當(dāng)收到相應(yīng)的自定義事件(即id為346798)時(shí),利用customEvent函數(shù)對(duì)事件進(jìn)行處理。

                    void UserWidget::slotGo()    //用戶(hù)定義控件的成員函數(shù)
{ mutex.lock();  
 if (! recv)
  recv = new UserThread(this, &mutex, &condition);
 recv->start();
 mutex.unlock();
}
void UserWidget::customEvent(QCustomEvent *e)   //用戶(hù)自定義事件處理函數(shù)
{ if (e->type()==346798) 
 {
  UserEvent *re = (UserEvent *) e;
        newstring = re->str();
    }
}
                
                  

在這個(gè)例子中,UserWidget對(duì)象中創(chuàng)建了新的線(xiàn)程UserThread,用戶(hù)可以利用這個(gè)線(xiàn)程實(shí)現(xiàn)一些周期性的處理(如接收底層發(fā)來(lái)的消息等),一旦滿(mǎn)足特定條件就提交一個(gè)用戶(hù)自定義的事件,當(dāng)UserWidget對(duì)象收到該事件時(shí),可以按需求做出相應(yīng)的處理,而一般情況下,UserWidget對(duì)象可以正常地執(zhí)行某些例行處理,而完全不受底層消息的影響。





回頁(yè)首


4、利用定時(shí)器機(jī)制實(shí)現(xiàn)多線(xiàn)程編程

為了避免Qt系統(tǒng)中多線(xiàn)程編程帶來(lái)的問(wèn)題,還可以使用系統(tǒng)中提供的定時(shí)器機(jī)制來(lái)實(shí)現(xiàn)類(lèi)似的功能。定時(shí)器機(jī)制將并發(fā)的事件串行化,簡(jiǎn)化了對(duì)并發(fā)事件的處理,從而避免了thread-safe方面問(wèn)題的出現(xiàn)。

在下面的例子中,同時(shí)有若干個(gè)對(duì)象需要接收底層發(fā)來(lái)的消息(可以通過(guò)Socket、FIFO等進(jìn)程間通信機(jī)制),而消息是隨機(jī)收到的,需要有一個(gè)GUI主線(xiàn)程專(zhuān)門(mén)負(fù)責(zé)接收消息。當(dāng)收到消息時(shí)主線(xiàn)程初始化相應(yīng)對(duì)象使之開(kāi)始處理,同時(shí)返回,這樣主線(xiàn)程就可以始終更新界面顯示并接收外界發(fā)來(lái)的消息,達(dá)到同時(shí)對(duì)多個(gè)對(duì)象的控制;另一方面,各個(gè)對(duì)象在處理完消息后需要通知GUI主線(xiàn)程。對(duì)于這個(gè)問(wèn)題,可以利用第3節(jié)中的用戶(hù)自定義事件的方法,在主線(xiàn)程中安裝一個(gè)事件過(guò)濾器,來(lái)捕捉從各個(gè)對(duì)象中發(fā)來(lái)的自定義事件,然后發(fā)出信號(hào)調(diào)用主線(xiàn)程中的一個(gè)槽函數(shù)。

另外,也可以利用Qt中的定時(shí)器機(jī)制實(shí)現(xiàn)類(lèi)似的功能,而又不必?fù)?dān)心Thread-safe問(wèn)題。下面就是有關(guān)的代碼部分:

在用戶(hù)定義的Server類(lèi)中創(chuàng)建和啟動(dòng)了定時(shí)器,并利用connect函數(shù)將定時(shí)器超時(shí)與讀取設(shè)備文件數(shù)據(jù)相關(guān)聯(lián):

                    Server:: Server(QWidget *parent) : QWidget(parent)
{
readTimer = new QTimer(this);   //創(chuàng)建并啟動(dòng)定時(shí)器
   connect(readTimer, SIGNAL(timeout()), this, SLOT(slotReadFile()));   //每當(dāng)定時(shí)器超時(shí)時(shí)調(diào)用函數(shù)slotReadFile讀取文件
   readTimer->start(100);
}
                
                  

slotReadFile函數(shù)負(fù)責(zé)在定時(shí)器超時(shí)時(shí),從文件中讀取數(shù)據(jù),然后重新啟動(dòng)定時(shí)器:

                    int Server::slotReadFile()    // 消息讀取和處理函數(shù)
{
  readTimer->stop();     //暫時(shí)停止定時(shí)器計(jì)時(shí)
  ret = read(file, buf );   //讀取文件
if(ret == NULL)
{    readTimer->start(100);     //當(dāng)沒(méi)有新消息時(shí),重新啟動(dòng)定時(shí)器
    return(-1);
}
  else
       根據(jù)buf中的內(nèi)容將消息分發(fā)給各個(gè)相應(yīng)的對(duì)象處理……;
readTimer->start(100);    //重新啟動(dòng)定時(shí)器
}
                
                  

在該程序中,利用了類(lèi)似輪循的方式定時(shí)對(duì)用戶(hù)指定的設(shè)備文件進(jìn)行讀取,根據(jù)讀到的數(shù)據(jù)內(nèi)容將信息發(fā)送到各個(gè)相應(yīng)的對(duì)象。用戶(hù)可以在自己的GUI主線(xiàn)程中創(chuàng)建一個(gè)Server類(lèi),幫助實(shí)現(xiàn)底層的消息接收過(guò)程,而本身仍然可以處理諸如界面顯示的問(wèn)題。當(dāng)各個(gè)對(duì)象完成處理后,通過(guò)重新啟動(dòng)定時(shí)器繼續(xù)進(jìn)行周期性讀取底層設(shè)備文件的過(guò)程。當(dāng)然,這種方法適合于各對(duì)象對(duì)事件的處理時(shí)間較短,而底層設(shè)備發(fā)來(lái)消息的頻率又相對(duì)較慢的情況。在這種情況下,上述方法完全可以滿(mǎn)足用戶(hù)的需求,而又避免了處理一些與線(xiàn)程并發(fā)有關(guān)的復(fù)雜問(wèn)題。

當(dāng)然,利用定時(shí)器機(jī)制實(shí)現(xiàn)多線(xiàn)程編程在某些方面具有一定的局限性,有關(guān)到底如何實(shí)現(xiàn)多線(xiàn)程編程,如何編寫(xiě)出效率更高的代碼,還有待于開(kāi)發(fā)者進(jìn)一步研究和探討。



參考資料

(1)Qt官方文檔 http://doc.trolltech.com/3.2/index.html

(2)Qt源代碼:QThread, QCustomEvent,QTimer.

(3)Advanced Programming in the UNIX Environment, W. Richard Stevens.

Qt中的多線(xiàn)程編程


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論