本篇文章給大家分享的是有關(guān)如何實(shí)現(xiàn)C++的可移植性和跨平臺(tái)開(kāi)發(fā),小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
在桓臺(tái)等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需制作網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都營(yíng)銷網(wǎng)站建設(shè),成都外貿(mào)網(wǎng)站建設(shè),桓臺(tái)網(wǎng)站建設(shè)費(fèi)用合理。概述
今天聊聊C++的可移植性問(wèn)題。如果你平時(shí)使用C++進(jìn)行開(kāi)發(fā),并且你對(duì)C++的可移植性問(wèn)題不是非常清楚,那么我建議你看看這個(gè)系列。即使你目前沒(méi)有跨平臺(tái)開(kāi)發(fā)的需要,了解可移植性方面的知識(shí)對(duì)你還是很有幫助的。
C++的可移植性這個(gè)話題很大,包括了編譯器、操作系統(tǒng)、硬件體系等很多方面,每一個(gè)方面都有很多內(nèi)容。鑒于本人能力、精力都有限,只能介紹每一個(gè)方面最容易碰到的問(wèn)題,供大伙兒參考。
后面我會(huì)分別從編譯器、C++語(yǔ)法、操作系統(tǒng)、第三方庫(kù)、輔助工具、開(kāi)發(fā)流程等方面進(jìn)行介紹。
編譯器
在跨平臺(tái)的開(kāi)發(fā)過(guò)程中,很多問(wèn)題都和編譯器有關(guān)。因此我們先來(lái)聊聊編譯器相關(guān)的問(wèn)題。
編譯器的選擇
首先,GCC是優(yōu)先要考慮支持的,因?yàn)閹缀跛胁僮飨到y(tǒng)平臺(tái)都有GCC可用。它基本上成了一個(gè)通用的編譯器了。如果你的代碼在A平臺(tái)的GCC能夠編譯通過(guò),之后拿到B平臺(tái)用類似版本的GCC編譯,一般也不會(huì)有太大問(wèn)題。因此GCC是肯定要考慮支持的。
其次,要考慮是否支持本地編譯器。所謂本地編譯器就是操作系統(tǒng)廠商自產(chǎn)的編譯器。例如:相對(duì)于Windows的本地編譯器就是Visual C++。相對(duì)于Solaris的本地編譯器就是SUN的CC。如果你對(duì)性能比較敏感或者想用到某些本地編譯器的高級(jí)功能,可能就得考慮在支持GCC的同時(shí)也支持本地編譯器。
編譯警告
編譯器是程序員的朋友,很多潛在的問(wèn)題(包括可移植性),編譯器都是可以發(fā)現(xiàn)并給出警告的,如果你平時(shí)注意這些警告信息,可以減少很多麻煩。因此我強(qiáng)烈建議:
1把編譯器的警告級(jí)別調(diào)高;
2不要輕易忽略編譯器的警告信息。
交叉編譯器
交叉編譯器的定義參見(jiàn)“維基百科”。通俗地說(shuō),就是在A平臺(tái)上編譯出運(yùn)行在B平臺(tái)上的二進(jìn)制程序。假設(shè)你要開(kāi)發(fā)的應(yīng)用是運(yùn)行在Solaris上,但是你手頭沒(méi)有能夠運(yùn)行Solaris的SPARC機(jī)器,這時(shí)候交叉編譯器就可以派上用場(chǎng)了。一般情況下都使用GCC來(lái)制作一個(gè)交叉編譯器,限于篇幅,這里就不深入聊了。有興趣的同學(xué)可以參見(jiàn)“這里”。
異常處理
上一個(gè)帖子“語(yǔ)法”由于篇幅有限,沒(méi)來(lái)得及聊異常,現(xiàn)在把和異常相關(guān)的部分單獨(dú)拿出來(lái)說(shuō)一下。
小心new分配內(nèi)存失敗
早期的老式編譯器生成的代碼,如果new失敗會(huì)返回空指針。我當(dāng)年用的Borland C++ 3.1似乎就是這樣的,現(xiàn)在這種編譯器應(yīng)該不多見(jiàn)了。如果你目前用的編譯器還有這種行為,那你就慘了。你可以考慮重載new操作符來(lái)拋出 bad_alloc異常,便于進(jìn)行異常處理。
稍微新式一點(diǎn)的編譯器,就不是僅僅返回空指針了。當(dāng)new操作符發(fā)現(xiàn)內(nèi)存告急,按照標(biāo)準(zhǔn)的規(guī)定(參見(jiàn)C++ 03標(biāo)準(zhǔn)18.4.2章節(jié)),它應(yīng)該去調(diào)用new_handler函數(shù)(原型為typedef void (*new_handler)();)。標(biāo)準(zhǔn)建議new_handler函數(shù)干如下三件事:
1、設(shè)法去多搞點(diǎn)內(nèi)存來(lái);
2、拋出bad_alloc異常;
3、調(diào)用abort()或者exit()退出進(jìn)程。
由于new_handler函數(shù)是可以被重新設(shè)置的(通過(guò)調(diào)用set_new_handler),所以上述的行為它都可能有。
綜上所述,new分配內(nèi)存失敗,有可能三種可能:
1、返回空指針;
2、拋出異常;
3、進(jìn)程立即終止。
如果你希望你的代碼具有較好的移植性,你就得把這三種情況都考慮到。
慎用異常規(guī)格
異常規(guī)格在我看來(lái)不是一個(gè)好東西,不信可以去看看《C++ Coding Standards - 101 Rules, Guidelines & Best Practices》的第75條。(具體有哪些壞處以后專門開(kāi)一個(gè)C++異常和錯(cuò)誤處理的帖子來(lái)聊)言歸正傳,按照標(biāo)準(zhǔn)(參見(jiàn)03標(biāo)準(zhǔn)18.6.2章節(jié)),如果一個(gè)函數(shù)拋到外面的異常沒(méi)有包含在該函數(shù)的異常規(guī)范中,那么應(yīng)該調(diào)用unexcepted()。但是并非所有編譯器生成的代碼都遵守標(biāo)準(zhǔn)(比如某些版本的VC編譯器)。如果你的需要支持的編譯器在異常規(guī)范上的行為不一致,那就得考慮去掉異常規(guī)范聲明。
不要跨模塊拋出異常
此處說(shuō)的模塊是指動(dòng)態(tài)庫(kù)。如果你的程序包含有多個(gè)動(dòng)態(tài)庫(kù),不要把異常拋到模塊的導(dǎo)出函數(shù)之外。畢竟現(xiàn)在C++還沒(méi)有ABI標(biāo)準(zhǔn)(估計(jì)將來(lái)也未必會(huì)有),跨模塊拋出異常會(huì)有很多不可預(yù)料的行為。
不要使用結(jié)構(gòu)化異常處理(SEH)
如果你從來(lái)沒(méi)有聽(tīng)說(shuō)過(guò)SEH,那就當(dāng)我沒(méi)說(shuō),跳過(guò)這段。如果你以前習(xí)慣于用SEH,在你打算寫(xiě)跨平臺(tái)代碼之前,要改掉這個(gè)習(xí)慣。包含有SEH的代碼只能在Windows平臺(tái)上編譯通過(guò),肯定無(wú)法跨平臺(tái)的。
關(guān)于catch(…)
照理說(shuō),catch(…)語(yǔ)句只能夠捕獲C++的異常類型,對(duì)于訪問(wèn)違例、除零錯(cuò)等非C++異常是無(wú)能為力的。但是某些情況下(比如某些VC編譯器),諸如訪問(wèn)違例、除零錯(cuò)也可以被catch(…)捕獲。所以,你如果希望代碼移植性好,就不能在程序邏輯中依賴上述catch(…)的行為。
硬件體系相關(guān)
這次聊的話題主要是和硬件體系有關(guān)的。比如你的程序需要支持不同類型的CPU(x86、SPARC、PowerPC),或者是同種類型不同字長(zhǎng)的CPU(比如x86和x86-64),這時(shí)候你就需要關(guān)心一下硬件體系的問(wèn)題。
基本類型的大小
C++中基本類型的大?。ㄕ加玫淖止?jié)數(shù))會(huì)隨著CPU字長(zhǎng)的變化而變化。所以,假如你要表示一個(gè)int占用的字節(jié)數(shù),千萬(wàn)不要直接寫(xiě)“4”(順便說(shuō)一下,直接寫(xiě)“4”還犯了Magic Number的大忌,詳見(jiàn)這里),而應(yīng)該寫(xiě)“sizeof(int)”;反過(guò)來(lái),如果你要定義一個(gè)大小必須為4字節(jié)的有符號(hào)整數(shù),也不要直接用int,要用預(yù)先typedef好的定長(zhǎng)類型(比如boost庫(kù)的int32_t、ACE庫(kù)的ACE_INT32、等)。
差點(diǎn)忘了,指針的大小也有上述的問(wèn)題,也要小心。
字節(jié)序
如果你沒(méi)聽(tīng)說(shuō)過(guò)“字節(jié)序”這玩意兒,請(qǐng)看“維基百科”。通俗地打個(gè)比方,在一個(gè)大尾序的機(jī)器上有一個(gè)4字節(jié)的整數(shù)0x01020304,通過(guò)網(wǎng)絡(luò)或者文件傳到一臺(tái)小尾序的機(jī)器上就會(huì)變成0x04030201;據(jù)說(shuō)還有一種中尾序的機(jī)器(不過(guò)我沒(méi)接觸過(guò)),上述整數(shù)會(huì)變成0x02010403。
如果你編寫(xiě)的應(yīng)用程序中涉及網(wǎng)絡(luò)通訊,一定要在記得進(jìn)行主機(jī)序和網(wǎng)絡(luò)序的翻譯;如果涉及跨機(jī)器傳輸二進(jìn)制文件,也要記得進(jìn)行類似的轉(zhuǎn)換。
內(nèi)存對(duì)齊
如果你不曉得“內(nèi)存對(duì)齊”是什么東東,請(qǐng)看“維基百科”。簡(jiǎn)單來(lái)說(shuō),出于CPU處理上的性能考慮,結(jié)構(gòu)體中的數(shù)據(jù)不是緊挨著的,而是要空開(kāi)一些間隔。這樣的話,結(jié)構(gòu)體中每個(gè)數(shù)據(jù)的地址正好都是某個(gè)字長(zhǎng)的整數(shù)倍。
由于C++標(biāo)準(zhǔn)中沒(méi)有定義內(nèi)存對(duì)齊的細(xì)節(jié),因此,你的代碼也不能依賴對(duì)齊的細(xì)節(jié)。凡是計(jì)算結(jié)構(gòu)體大小的地方,都老老實(shí)實(shí)寫(xiě)上sizeof()。
有些編譯器支持#pragma pack預(yù)處理語(yǔ)句(可以用來(lái)修改對(duì)齊字長(zhǎng)),不過(guò)這種語(yǔ)法不是所有編譯器都支持,要慎用。
移位操作
對(duì)于有符號(hào)整數(shù)的右移操作,有些系統(tǒng)默認(rèn)使用算數(shù)右移(最高的符號(hào)位不變),有些默認(rèn)使用邏輯右移(最高的符號(hào)位補(bǔ)0)。所以,不要對(duì)有符號(hào)整數(shù)進(jìn)行右移操作。順便說(shuō)一下,即使沒(méi)有移植性問(wèn)題,代碼中也盡量少用移位運(yùn)算符。那些企圖用移位運(yùn)算來(lái)提高性能的同學(xué)更要注意了,這么干不但可讀性很差,而且吃力不討好。只要不太弱智的編譯器,都會(huì)自動(dòng)幫你搞定這種優(yōu)化,無(wú)須程序員操心。
操作系統(tǒng)
上一個(gè)帖子提到了“硬件體系”相關(guān)的話題,今天來(lái)說(shuō)說(shuō)和操作系統(tǒng)相關(guān)的話題。C++跨平臺(tái)開(kāi)發(fā)中和OS相關(guān)的瑣事挺多,所以今天會(huì)啰嗦比較長(zhǎng)的篇幅,請(qǐng)列位看官見(jiàn)諒 :-)
為了不繞口,以下把Linux和各種Unix統(tǒng)稱為Posix系統(tǒng)。
文件系統(tǒng)(FileSystem以下簡(jiǎn)稱FS)
剛開(kāi)始搞跨平臺(tái)開(kāi)發(fā)的新手,多半都會(huì)碰上和FS相關(guān)的問(wèn)題。所以先來(lái)聊一下FS。歸納下來(lái),開(kāi)發(fā)中容易碰上的FS差異主要有如下幾個(gè):目錄分隔符的差異;大小寫(xiě)敏感的差異;路徑中禁用字符的差異。
為了應(yīng)對(duì)上述差異,你要注意如下幾點(diǎn):
1、文件和目錄命名要規(guī)范
在給文件和目錄命名時(shí),盡量只使用字母和數(shù)字。不要在同一個(gè)目錄下放兩個(gè)名稱相似(名稱中只有大小寫(xiě)不同,例如foo.cpp與Foo.cpp)的文件。不要使用某些OS的保留字(例如aux、con、nul、prn)作文件名或目錄名。
補(bǔ)充一下,剛才說(shuō)的命名,包括了源代碼文件、二進(jìn)制文件和運(yùn)行時(shí)創(chuàng)建的其它文件。
2、#include語(yǔ)句要規(guī)范
當(dāng)你寫(xiě)#include語(yǔ)句時(shí),要注意使用正斜線“/”(比較通用)而不要使用反斜線“\”(僅在Windows可用)。#include語(yǔ)句中的文件和目錄名要和實(shí)際名稱保持大小寫(xiě)完全一致。
3、代碼中涉及FS操作,盡量使用現(xiàn)成的庫(kù)
已經(jīng)有很多成熟的、用于FS的第三方庫(kù)(比如boost::filesystem)。如果你的代碼涉及到FS的操作(比如目錄遍歷),盡量使用這些第三方庫(kù),可以幫你省不少事情。
★文本文件的回車CR/換行LF
由于幾個(gè)知名的操作系統(tǒng)對(duì)回車/換行的處理不一致,導(dǎo)致了這個(gè)煩人的問(wèn)題。目前的局面是:Windows同時(shí)使用CR和LF;Linux和大部分的Unix使用LF;蘋(píng)果的Mac系列使用CR。
對(duì)于源代碼管理,好在很多版本管理軟件(比如CVS、SVN)都會(huì)智能地處理這個(gè)問(wèn)題,讓你從代碼庫(kù)取回本地的源碼能適應(yīng)本地的格式。
如果你的程序需要在運(yùn)行時(shí)處理文本文件,要留意本文方式打開(kāi)和二進(jìn)制方式打開(kāi)的區(qū)別。另外,如果涉及跨不同系統(tǒng)傳輸文本文件,要考慮進(jìn)行適當(dāng)?shù)奶幚怼?br/> ★文件搜索路徑(包括搜索可執(zhí)行文件和動(dòng)態(tài)庫(kù))
在Windows下,如果要執(zhí)行文件或者加載動(dòng)態(tài)庫(kù),一般會(huì)搜索當(dāng)前目錄;而Posix系統(tǒng)則不盡然。所以如果你的應(yīng)用涉及到啟動(dòng)進(jìn)程或加載動(dòng)態(tài)庫(kù),就要小心這個(gè)差異。
★環(huán)境變量
對(duì)于上述提到的搜索路徑問(wèn)題,有些同學(xué)想通過(guò)修改PATH和LD_LIBRARY_PATH來(lái)引入當(dāng)前路徑。假如使用這種方法,建議你只修改進(jìn)程級(jí)的環(huán)境變量,不要修改系統(tǒng)級(jí)的環(huán)境變量(修改系統(tǒng)級(jí)有可能影響到同機(jī)的其它軟件,產(chǎn)生副作用)。
★動(dòng)態(tài)庫(kù)
如果你的應(yīng)用程序使用動(dòng)態(tài)庫(kù),強(qiáng)烈建議動(dòng)態(tài)庫(kù)導(dǎo)出標(biāo)準(zhǔn)C風(fēng)格的函數(shù)(盡量不要導(dǎo)出類)。如果在Posix系統(tǒng)中加載動(dòng)態(tài)庫(kù),切記慎用RTLD_GLOBAL標(biāo)志位。這個(gè)標(biāo)志位會(huì)Enable全局符號(hào)表,有可能會(huì)導(dǎo)致多個(gè)動(dòng)態(tài)庫(kù)之間的符號(hào)名沖突(一旦碰到這種事,會(huì)出現(xiàn)匪夷所思的運(yùn)行時(shí)錯(cuò)誤,極難調(diào)試)。
★服務(wù)/看守進(jìn)程
如果你不清楚服務(wù)和看守進(jìn)程的概念,請(qǐng)看維基百科(這里和這里)。為了敘述方便,以下統(tǒng)稱服務(wù)。
由于C++開(kāi)發(fā)的模塊大部分是后臺(tái)模塊,經(jīng)常會(huì)碰到服務(wù)的問(wèn)題。編寫(xiě)服務(wù)需要調(diào)用好幾個(gè)系統(tǒng)相關(guān)的API,導(dǎo)致了與操作系統(tǒng)的緊密耦合,很難用一套代碼搞定。因此比較好的辦法是抽象出一個(gè)通用的服務(wù)外殼,然后把業(yè)務(wù)邏輯代碼作為動(dòng)態(tài)庫(kù)掛載到它下面。這樣的話,至少保證了業(yè)務(wù)邏輯的代碼只需要一套;服務(wù)外殼的代碼雖然需要兩套(一個(gè)用于Windows、一個(gè)用于Posix),但他們是業(yè)務(wù)無(wú)關(guān)的,可以很方便地重用。
★默認(rèn)棧大小
不同的操作系統(tǒng),棧的默認(rèn)大小差別很大,從幾十KB(據(jù)說(shuō)Symbian只有12K,真摳門)到幾MB不等。因此你事先要打聽(tīng)一下目標(biāo)系統(tǒng)的默認(rèn)棧大小,如果碰上像Symbian這樣摳門的,可以考慮用編譯器選項(xiàng)調(diào)大。當(dāng)然,養(yǎng)成“不在棧上定義大數(shù)組/大對(duì)象”的好習(xí)慣也很重要,否則再大的棧也會(huì)被撐爆的。
多線程
最近一個(gè)多月寫(xiě)的帖子比較雜,導(dǎo)致本系列又好久沒(méi)更新了。結(jié)果又有網(wǎng)友在評(píng)論中催我了,搞得我有點(diǎn)囧。今天趕緊把多線程篇補(bǔ)上。上次聊操作系統(tǒng) 的時(shí)候,由于和OS有關(guān)的話題比較瑣碎,雜七雜八說(shuō)了一大堆。當(dāng)時(shí)一看篇幅有點(diǎn)長(zhǎng),就把多進(jìn)程和多線程的部分給留到后面了。
★編譯器
◇關(guān)于C運(yùn)行庫(kù)選項(xiàng)
先來(lái)說(shuō)一個(gè)很基本的問(wèn)題:關(guān)于C運(yùn)行庫(kù)(后面簡(jiǎn)稱CRT:C Run-Time)的設(shè)置。本來(lái)不想聊這么低級(jí)的問(wèn)題,但周圍有好幾個(gè)人都在這個(gè)地方吃過(guò)虧,所以還是講一下。
大部分C++編譯器都會(huì)自帶有CRT(可能還不止一個(gè))。某些編譯器自帶的CRT可能會(huì)根據(jù)線程的支持分為單線程CRT和多線程CRT兩類。當(dāng)你要進(jìn)行多線程開(kāi)發(fā)的時(shí)候,別忘了確保相關(guān)的C++工程項(xiàng)目使用的是多線程的CRT。否則會(huì)死得很難看。
尤其當(dāng)你使用Visual C++創(chuàng)建工程項(xiàng)目,更加要小心。如果新建的工程項(xiàng)目是不含MFC的(包括Console工程和Win32工程),那工程的默認(rèn)設(shè)置會(huì)是使用“單線程CRT”,如下圖所示:
◇關(guān)于優(yōu)化選項(xiàng)
“優(yōu)化選項(xiàng)”是另一個(gè)很關(guān)鍵的編譯器相關(guān)話題。有些編譯器提供號(hào)稱很牛X的優(yōu)化選項(xiàng),但是某些優(yōu)化選項(xiàng)可能會(huì)有潛在的風(fēng)險(xiǎn)。編譯器可能自作主張打亂執(zhí)行指令的順序,從而導(dǎo)致出乎意料的線程競(jìng)態(tài)問(wèn)題(Race Condition,詳細(xì)解釋看“這里 ”)。劉未鵬同學(xué)在“C++多線程內(nèi)存模型 ”里舉了幾個(gè)典型的例子,大伙兒可以去瞧一瞧。
建議只使用編譯器常規(guī)的速度優(yōu)化選項(xiàng)即可。其它那些花哨的優(yōu)化選項(xiàng),增加的效果未必明顯,但是潛在的風(fēng)險(xiǎn)不小。實(shí)在不值得冒險(xiǎn)。
以GCC為例:建議用-O2 選項(xiàng)即可(其實(shí)-O2 是一堆選項(xiàng)的集合),沒(méi)必要冒險(xiǎn)用-O3 (除非你有很充足的理由)。除了-O2 和-O3 之外,GCC還有一大坨(估計(jì)有上百個(gè))其它的優(yōu)化選項(xiàng)。如果你企圖用當(dāng)中的某個(gè)選項(xiàng),一定要先把它的特性、可能的副作用都摸清楚,否則將來(lái)死都不知道怎么死的。
★線程庫(kù)的選擇
由于當(dāng)前的C++ 03標(biāo)準(zhǔn)幾乎沒(méi)有涉及線程相關(guān)的內(nèi)容(即使將來(lái)C++ 0x包含了線程的標(biāo)準(zhǔn)庫(kù),編譯器廠商的支持在短期內(nèi)也未必全面),所以在未來(lái)很長(zhǎng)的一段時(shí)間,跨平臺(tái)的多線程支持還是要依賴第三方庫(kù)。所以線程庫(kù)的選擇是大大滴重要。下面大致介紹一下幾個(gè)知名的跨平臺(tái)線程庫(kù)。
◇ACE
先說(shuō)一下ACE這個(gè)歷史悠久的庫(kù)。如果你之前從未接觸過(guò)它,先看“這里 ”掃盲。從ACE的全稱(Adaptive Communication Environment)來(lái)看,它應(yīng)該是以“通訊”為主業(yè)。不過(guò)ACE對(duì)“多線程”這個(gè)副業(yè)的支持還是非常全面的,比如互斥鎖(ACE_Mutex)、條件變量(ACE_Condition)、信號(hào)量(ACE_Semaphore)、柵欄(ACE_Barrier)、原子操作(ACE_Atomic_Op)等等。對(duì)某些類型比如ACE_Mutex還細(xì)分為線程讀寫(xiě)鎖(ACE_RW_Thread_Mutex)、線程遞歸鎖(ACE_Recursive_Thread_Mutex)等等。
除了支持很全面,ACE還有另一個(gè)很明顯的優(yōu)點(diǎn),就是對(duì)各種操作系統(tǒng)平臺(tái)及其自帶的編譯器支持很好。包括一些老式的編譯器(比如VC6),它也能夠支持(此處所說(shuō)的支持 ,不光是能編譯通過(guò),而且要能穩(wěn)定運(yùn)行)。這個(gè)優(yōu)點(diǎn)對(duì)于跨平臺(tái)開(kāi)發(fā)那是相當(dāng)相當(dāng)?shù)蚊黠@。
那缺點(diǎn)捏?由于ACE開(kāi)工的年頭很早(大概是上世紀(jì)九十年代中期),那會(huì)兒很多C++的老特性都還沒(méi)出來(lái)(更別提新特性了),所以感覺(jué)ACE整個(gè)的風(fēng)格比較老氣,遠(yuǎn)不如boost那么時(shí)髦前衛(wèi)。
◇boost::thread
boost::thread正好和ACE形成鮮明對(duì)照。這玩意貌似從boost 1.32版本開(kāi)始引入,年頭比ACE短。不過(guò)得益于boost里一幫大牛的支持,發(fā)展還是蠻快的。到目前的boost 1.38版本,也能夠支持許多特性了(不過(guò)似乎沒(méi)ACE多)。鑒于很多C++標(biāo)準(zhǔn)委員會(huì)的成員云集在boost社區(qū)中,隨著時(shí)間的推移,boost::thread終將成為C++線程的明日之星,前途無(wú)量啊!
boost::thread的缺點(diǎn)就是支持的編譯器不夠多,尤其是一些老式 編譯器(很多boost的子庫(kù)都有此問(wèn)題,多半因?yàn)橛昧艘恍└呒?jí)的模板語(yǔ)法)。這對(duì)于跨平臺(tái)而言一個(gè)比較明顯的問(wèn)題。
◇wxWidgets 和QT
wxWidgets和QT都是GUI界面庫(kù),但是它們也都內(nèi)置和對(duì)線程的支持。wxWidgets線程的簡(jiǎn)介可以看“這里 ”,關(guān)于QT線程的簡(jiǎn)介可以看“這里 ”。這兩個(gè)庫(kù)對(duì)線程的支持差不多,都提供了諸如mutex、condition、semaphore等常用的機(jī)制。不過(guò)特性沒(méi)有ACE豐富。
◇如何權(quán)衡
對(duì)于開(kāi)發(fā)GUI軟件并已經(jīng)用上了wxWidgets或者QT,那你可以直接用它們內(nèi)置的線程庫(kù)(前提是你只用到基本的線程功能)。由于它們內(nèi)置的線程庫(kù),特性稍嫌單薄。萬(wàn)一你需要某高級(jí)的線程功能,那得考慮替換成boost::thread或ACE。
至于boost::thread和ACE的取舍,主要得看軟件的需求了。如果你要支持的平臺(tái)挺多挺雜,那建議選用ACE,以免碰上編譯器不支持的問(wèn)題。如果你只需要支持少數(shù)幾個(gè)主流的平臺(tái)(比如Windows、Linux、Mac),那建議用boost::thread。畢竟主流操作系統(tǒng)上的編譯器,對(duì)boost的支持還是蠻好的。
★編程上的注意事項(xiàng)
其實(shí)多線程開(kāi)發(fā),需要注意的地方挺多的,我只能大致列幾個(gè)印象比較深的注意事項(xiàng)。
◇關(guān)于volatile
說(shuō)到多線程編程可能碰到的陷阱,那就不得不提到volatile 關(guān)鍵字。如果你對(duì)它還不甚了解,先看“這里 ”掃盲一下。由于C++ 98和C++ 03標(biāo)準(zhǔn)都沒(méi)有定義多線程的內(nèi)存模型,而標(biāo)準(zhǔn)中也就volatile 和線程沾點(diǎn)兒邊。結(jié)果導(dǎo)致C++社區(qū)中有相當(dāng)多的口水都集中在volatile 身上(其中有不少C++大牛的口水)。有鑒于此,我這里就不再多啰嗦了。推薦幾個(gè)大牛的文章:Andrei Alexandrescu 的文章“這里 ”、還有Hans Boehm的文章“這里 ”和“這里 ”。大伙兒自個(gè)兒去拜讀一下。
◇關(guān)于原子操作
有些同學(xué)光知道多個(gè)線程的競(jìng)爭(zhēng)寫(xiě) 需要加鎖,卻不知道多個(gè)讀 單個(gè)寫(xiě) 也需要保護(hù)。比如有某個(gè)整數(shù)int nCount = 0x01020304;在并發(fā)狀態(tài)下,一個(gè)寫(xiě)線程去修改它的值nCount = 0x05060708;另一個(gè)讀線程去獲取該值。那么讀線程有沒(méi)有可能讀取到一個(gè)“壞”的(比如0x05060304)數(shù)據(jù)捏?
數(shù)據(jù)是否壞掉,取決于對(duì)nCount的讀和寫(xiě)是否屬于原子操作。而這就依賴于很多硬件相關(guān)的因素了(包括CPU的類型、CPU的字長(zhǎng)、內(nèi)存對(duì)齊的字節(jié)數(shù)等)。在某些情況下,確實(shí)可能出現(xiàn)數(shù)據(jù)壞掉。
由于我們討論的是跨平臺(tái)的開(kāi)發(fā),天曉得將來(lái)你的代碼會(huì)在啥樣的硬件環(huán)境下執(zhí)行。所以在處理類似問(wèn)題的時(shí)候,還是要用第三方庫(kù)提供的原子操作類/函數(shù)(比如ACE的Atomic_Op)來(lái)確保安全。
◇關(guān)于對(duì)象的析構(gòu)
在之前的系列帖子“C++對(duì)象是怎么死的? ”里面,已經(jīng)分別介紹了Win32平臺(tái)和Posix平臺(tái)下線程的非自然死亡問(wèn)題。
由于上述幾個(gè)跨平臺(tái)的線程庫(kù)底層還是要調(diào)用操作系統(tǒng)自帶的線程API,所以大伙兒還是要盡大努力確保所有線程都能夠自然死亡。
以上就是如何實(shí)現(xiàn)C++的可移植性和跨平臺(tái)開(kāi)發(fā),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。