999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

基于Qt的線程池服務器的研究與應用

2014-01-01 03:10:00張衛強
無線電通信技術 2014年6期
關鍵詞:方法

劉 飛,張衛強,羅 彤

(寧波大學信息科學與工程學院,浙江寧波315211)

0 引言

傳統的網絡服務器模型中,服務器收到一個客戶端請求后,創建一個新線程,由該線程執行任務,任務完成后,線程退出,即“即時創建,即時刪除”,對服務器來說創建線程已經比創建進程節約了不少時間,但是如果大量的客戶端對服務器過于頻繁的進行連接,該服務器就將在創建和刪除線程的過程中耗費大量時間[1]。所以減少創建和銷毀對象,尤其是減少很耗資源的對象成為提高服務程序效率的重要手段之一。線程池是一組預先創建的線程,快速、容易地處理收到的業務。比起傳統的“即時創建,即時刪除”的模型,該類型服務器節省了創建和回收線程的開銷,響應更快,效率更高[2]。

為高圖形用戶界面的響應速度,Qt提供豐富的多線程編程支持[],而為減少Qt創建和刪除線程的開銷,Qt又提供了線程池技術的支持。為降低基于Qt的網絡服務器頻繁的創建線程的開銷,本文就Qt線程池技術進行分析,研究其運行機制,并運用該技術創建一個服務器模型。

1 Qt的線程池類和QTcpServer類

Qt提供了與平臺無關的線程類,在Qt系統中與線程池相關的最重要的類是QThreadPool和QRunnable。QThreadPool用于管理一批線程,它負責管理和回收單個線程[4]。每個 Qt應用可通過QThreadPool::globalInstance()獲得一個全局的QThreadPool對象。QRunable類表示一個任務或者一段被執行代碼的一個接口。使用QThreadPool類來運行一個QRunnable對象。把一個QRunnable放入了QThreadPool的運行隊列中,只要線程是可見的,QRunnable將會被拾起并且在那個線程里運行,QRunnable是一種輕量級的、以“run and forget”方式來在另一個線程開啟任務的抽象類,為了實現這一功能,要做的全部事情是派生QRunnable類,并實現純虛函數方法 run()[5]。

QTcpServer類不是QAbstractSocket抽象套接字類,而是繼承于QObject基類,為編寫TCP客戶端和服務器應用程序提供一個 TCP基礎服務類[6]。QTcpSocket類提供了基于TCP協議的通用接口,為監聽每一個客戶端的連接,可通過調用listen()函數來實現,每當服務器收到一個客戶端的連接請求時就會發射newConnection()信號,如果要接受待處理的連接,則可通過調用nextPendingConnection()函數,并返回一個連接的 QTcpSocket()套接字[7],該套接字作為服務端的一個子對象,可以通過使用這個返回的套接字和客戶端進行連接,這就意味著當QTcpServer對象要銷毀時,該套接字也會隨之被自動刪除,即不能在其他線程中使用該套接字,如果想在其他線程中繼續使用該套接字,那么需要重載void incomingConnection(int socketDescriptor)函數,這個函數將新創建一個QTcpSocket套接字,該函數中socketDescriptor參數是新連接的套接字描述符,然后在一個整形的待連接鏈表中將套接字存儲,最后發射信號newConnection()。

2 線程池機制

2.1 線程池技術介紹

線程池就是在進程中先創建好一批線程,當有任務到來時,就從創建好的線程中取出一個線程來處理該任務,任務結束之后,將線程置為空閑,放回線程池中繼續等待下次任務的到來[8],工作過程如圖1所示。

2.2 基于Qt的線程池機制

在Qt中通過globalInstance()方法,每個 Qt的應用程序都可獲得一個全局的QThreadPool對象。

theInstance()函數功能通過Q_GLOBAL_STATIC(QThreadPool,theInstance)宏實現,以此返回一個全局的QThreadPool對象。此外由于QThreadPool類繼承QObject,在QThreadPool類中可以使用Qt提供的信號與槽機制。圖1為線程池工作原理。

圖1 線程池工作原理

通過上面介紹的函數就可以得到一個全局的QthreadPool,但是為了能夠調用該線程池中的一個線程,還需要提供繼承于QRunnable的一個類,從而實現其中的run方法。然后創建一個該類的對象,傳遞給void QThreadPool::Start(QRunnable*runnable,int priority),該函數具體實現如下所示。

該方法通過Q_D宏獲取QThreadPool命名為d的數據結構,真正開始QThreadPool一個線程是通過enqueueTask()方法實現的。

enqueueTask()方法將runnable放入隊列中來管理,并喚醒QThreadPool管理的線程池中的一個線程實現一個繼承QRunnable類的run方法。

在默認情況下,QthreadPool將能夠自動刪除創建的 QRunnable對象。使用 void QRunnable::setAutoDelete(bool autoDelete)方法可以改變這一默認行為,但是該標志必須在調用QThreadPool::Start()之前被設置,否則將會出現錯誤。

QThreadPool支持在QRunnable::run方法中通過調用tryStart(this)來多次執行相同的QRunnable。當最后一個線程退出run函數后,如果autoDelete啟用的話,將刪除QRunnable對象。在autoDelete啟用的情況下,調用start()方法多次執行同一QRunnable會產生競態,因此要避免這樣做。

通過void setExpiryTimeout(int expiryTimeout)函數來設置線程的過期時間,默認過期時間為30 s。如果設置expriyTimeout為一個負數,則代表禁止使用超時機制。如果要規定最大的線程數可通set-MaxThreadCount(int maxThreadCount)來設置,其參數maxThreadCount為要設置的數量,通過 void maxThreadCount()可以查詢可使用的最大線程數。為了確保該線程被釋放后可循環使用,可以通過函數void releaseThread()釋放該線程的,以便它可以被再次使用。

3 Qt線程池服務器模型的建立

在下面的步驟中,將利用線程池技術創建一個服務器模型,以此介紹線程池的創建步驟,并通過命令客戶端對創建的服務器進行測試。

3.1 主要相關代碼

首先創建一個繼承QTcpServer的一個類,在該類的實現方法中監聽客戶端的連接每當有客戶端連接時都會調用virtual void incomingConnection(int socketDescriptor)函數[9,10],因此處理這個請求的過程就可以在這個函數中實現,對一個線程池的服務器,每當客戶端試圖連接的時候,服務器從線程池中啟動一個線程,負責對這個客戶端進行服務,所以,incomingConnection()這個函數所要做的就是建立一個線程,進而對客戶端進行服務。代碼如下,先添加類的前置聲明:

在myserver.cpp文件中,首先在構造函數中通過globalInstance()函數獲取一個全局QThreadPool對象,并設置最大線程數為20,之后實現監聽客戶端連接。

該服務器監聽到客戶端試圖建立一個套接字連接,該套接字將自動分配一個 SocketDescriptor標識,該標識會在服務器連接中使用,應當提供給每一個線程。

服務器在監聽到客戶端試圖建立socket連接時,會為此socket分配一個標識socketDescriptor,該標識在建立服務器連接時使用,所以應提供給每一個線程。接下來派生QRunnable類,并實現純虛函數run()。

3.2 程序運行測試

在Linux環境下編譯運行服務器程序結果如圖2所示。

圖2 編譯運行

此時,如圖2所示服務器已經啟動,下面用Linux命令終端的telnet程序模擬一個客戶端,在telnet程序中輸入命令:open 127.0.0.1 1234(此處的127.0.01為程序中的設置的IP地址,即IPV4的本地主機地址,端口號是1234),請求服務器進行連接,并對其進行測試,測試結果如圖3、圖4所示。

圖3 客戶端

圖4 服務器端

通過以上步驟,利用線程池技術完成了一個服務器的創建,即使用 QThreadPool類來運行一個QRunnable對象,它維護了一個線程池。當客戶端請求連接時,服務器端調用已經創建好的線程池中的一個線程對該客戶端請求進行處理,如圖3所示,服務器將一個簡單的字符串“Hello world!!”傳遞給客戶端,并在命令客戶端顯示,此時服務器端打印出為該客戶端服務的線程ID,如圖4所示。通過以上測試,運用線程池技術實現了服務器與客戶端之間的通信。

4 結束語

針對目前多線程服務器在接受客戶端頻繁連接會增加開銷這一弱點,提出利用Qt線程池技術減少程序中頻繁創建線程的開銷的優勢,在服務器模型中加入線程池技術的支持,即利用QThreadPool線程池來管理一組線程,每當有客戶端連接時,就有單個線程對象來處理客戶端請求并交由該線程池管理和回收,從而減少了服務器頻繁創建線程的開銷,提高服務器工作效率。但是由于QRunnable并非QObject類,它沒有一個內置的與其他組件顯式通訊的方法,必須使用底層的線程原語(比如收集結構的枷鎖保護隊列等)來親自編寫代碼。

[1] 曾云.基于ARM+QT平臺的嵌入式賓館客服系統軟件設計[D].上海:東華大學,2011:25-31.

[2] 劉新強,曾兵義.用線程池解決服務器并發請求的方案設計[J].現代電子技術,2011,34(15):141 -143.

[3] 黃宇東,胡躍明,陳安.基于Qt的多線程技術應用于研究[J].軟件導刊,2009,8(10):40-42.

[4] 趙祖龍.基于Qt/Embedded的嵌入式跨平臺聊天系統設計[J].信息技術,2010,34(12):144 -147.

[5] 蔡志明,盧傳富,李立夏.精通Qt4編程[M].北京:電子工業出版社,2008.

[6] 崔弘珂.一種空間環境下的TCP傳輸技術研究[J].無線電通信技術,2011,37(4):21-24.

[7] 丁林松,黃麗琴.Qt4圖形設計與嵌入式開發[M].北京:人民郵電出版社,2009.

[8] 汪成林.linux環境下基于SSL的安全文件傳輸系統研究[D].杭州:浙江工業大學,2012:38-45.

[9] 馮艷紅,何加銘,楊任爾,等.基于Android藍牙技術的健康服務系統設計[J].無線電通信技術,2014,40(1):61-64.85-88.

[10]馬睿.基于Qt的TCP網絡編程研究與應用[J].福建電腦,2010,26(11):138 -139.

猜你喜歡
方法
中醫特有的急救方法
中老年保健(2021年9期)2021-08-24 03:52:04
高中數學教學改革的方法
河北畫報(2021年2期)2021-05-25 02:07:46
化學反應多變幻 “虛擬”方法幫大忙
變快的方法
兒童繪本(2020年5期)2020-04-07 17:46:30
學習方法
用對方法才能瘦
Coco薇(2016年2期)2016-03-22 02:42:52
最有效的簡單方法
山東青年(2016年1期)2016-02-28 14:25:23
四大方法 教你不再“坐以待病”!
Coco薇(2015年1期)2015-08-13 02:47:34
賺錢方法
捕魚
主站蜘蛛池模板: 国产成人麻豆精品| www亚洲天堂| 真实国产乱子伦高清| 亚洲狠狠婷婷综合久久久久| 亚洲国产av无码综合原创国产| 欧美视频在线不卡| 色悠久久久久久久综合网伊人| 高清无码手机在线观看 | 久久99精品久久久久纯品| 99re在线视频观看| 丝袜美女被出水视频一区| 欧美一区国产| 99久久国产综合精品2023| 国产精品天干天干在线观看| 国产成人高清在线精品| 国产成人高清亚洲一区久久| 国产精品亚洲专区一区| 免费xxxxx在线观看网站| 国产在线一区视频| 91午夜福利在线观看| 久久综合九九亚洲一区| 国产精品不卡片视频免费观看| 影音先锋亚洲无码| 女人18毛片久久| 无码国内精品人妻少妇蜜桃视频| 久久国产香蕉| 97免费在线观看视频| 一本一道波多野结衣一区二区 | 激情在线网| 国产人前露出系列视频| 蜜臀av性久久久久蜜臀aⅴ麻豆| 老司国产精品视频91| 成人自拍视频在线观看| 亚洲青涩在线| 少妇精品在线| 国产一级毛片在线| 亚洲精品麻豆| 欧美日韩中文国产va另类| P尤物久久99国产综合精品| 欧美国产综合色视频| 欧美69视频在线| 无码有码中文字幕| 亚洲日本中文综合在线| 亚洲综合国产一区二区三区| 奇米影视狠狠精品7777| 真实国产乱子伦视频| 日本黄色a视频| 9啪在线视频| 欧美人在线一区二区三区| 亚洲最大福利视频网| 国产不卡在线看| 超碰aⅴ人人做人人爽欧美| 青青青国产在线播放| 亚洲水蜜桃久久综合网站| 综合亚洲网| 永久免费无码成人网站| 亚洲欧美另类中文字幕| 91一级片| av在线无码浏览| 亚洲欧洲自拍拍偷午夜色| 激情六月丁香婷婷| 国产精品毛片一区| 天天躁夜夜躁狠狠躁图片| 国内精品小视频福利网址| 58av国产精品| 亚洲欧美一区二区三区蜜芽| 亚洲av色吊丝无码| 天天综合色网| 久久性妇女精品免费| 精品少妇人妻无码久久| 伊人中文网| 久久免费视频6| 少妇精品久久久一区二区三区| 日韩欧美中文在线| 在线观看亚洲国产| 欧美有码在线观看| 日本黄色a视频| 亚洲综合18p| 久久久久无码精品| 国产aⅴ无码专区亚洲av综合网| 国产99在线| 国产欧美性爱网|