多線程編程精髓(四)

(1)鎖使用實(shí)踐經(jīng)驗(yàn)總結(jié):1.盡量減少鎖的使用稻扬,加鎖和解鎖會(huì)有系統(tǒng)開銷蹦哼,臨界區(qū)的代碼是不能并發(fā)執(zhí)行的,進(jìn)入臨界區(qū)次數(shù)頻繁俩檬,線程競爭過于激烈則會(huì)陷入阻塞萎胰,讓出CPU,導(dǎo)致

多次無效的上下文切換棚辽,可使用無鎖隊(duì)列替換技竟。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.明確鎖的范圍,減少鎖的粒度屈藐,減小鎖使用粒度指的是盡量減小鎖作用的臨界區(qū)代碼范圍榔组,臨界區(qū)的代碼范圍越小,多個(gè)線程排隊(duì)進(jìn)入臨界區(qū)的時(shí)間就會(huì)越

短估盘,改寫代碼順序結(jié)構(gòu)瓷患,也可以使用{ }花括號(hào)確定鎖的臨界區(qū)代碼范圍最小化 。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 3.避免死鎖的出現(xiàn),使用 RAII 技術(shù)將加鎖和解鎖代碼封裝起來,避免出口處沒有解鎖遣妥;線程退出時(shí)一定要及時(shí)釋放持有的鎖擅编;多線程請求鎖的方向一致,比如都是

先請求A鎖箫踩,再請求B鎖爱态,不要出現(xiàn)其他線程先請求B鎖,再請求A鎖境钟;當(dāng)同一線程重復(fù)請求鎖時(shí)锦担,明確是遞增鎖引用計(jì)數(shù),還是會(huì)阻塞抑或是直接獲得鎖慨削。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4,避免活鎖的出現(xiàn)洞渔,所謂活鎖就是套媚,當(dāng)多個(gè)線程使用 trylock 系列的函數(shù)時(shí),由于多個(gè)線程相互謙讓磁椒,導(dǎo)致即使在某段時(shí)間內(nèi)鎖資源是可用的堤瘤,也可能導(dǎo)致需要

鎖的線程拿不到鎖,因此避免不要過多的線程使用 trylock 請求鎖導(dǎo)致資源浪費(fèi)浆熔。

(2)線程局部存儲(chǔ):每個(gè)線程都擁有自己的局部屬性本辐,并行不悖,互不干擾医增,該屬性會(huì)一直存在直到線程退出慎皱。

? ? ? ? ? 1.? windows下的系統(tǒng)Tls函數(shù)的 API:

? ? ? ? ? ? ? ? ? ? DWORD ? TlsAlloc();? //獲得一個(gè)線程局部存儲(chǔ)塊的索引,調(diào)用失敗返回TLS_OUT_OF_INDEXES(0xFFFFFFFF),否則返回正確索引值

? ? ? ? ? ? ? ? ? ? LPVOID ?? TlsGetValue(DWORD dwTlsIndex); ? //使用索引塊獲取內(nèi)存存儲(chǔ)的數(shù)據(jù)

? ? ? ? ? ? ? ? ? ? BOOL ? ? ?? TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue); // 使用索引塊設(shè)置內(nèi)存存儲(chǔ)數(shù)據(jù)

? ? ? ? ? ? ? ? ? ? BOOL ? ? ?? TlsFree(DWORD dwTlsIndex);? //釋放存儲(chǔ)區(qū)域

? ? ? ?? 此外Microsoft VC++ 編譯器還提供如右所示方法 定義線程局部變量:__declspec(thread)? int? g_mydata = 1;

? ? ? ? ? ? 2. linux下系統(tǒng)的NTPL 提供了API函數(shù):

? ? ? ? ? ? ? ? ? ?? int ? ? pthread_key_create(pthread_key_t* key,void(*destructor)(void*));? //調(diào)用成功會(huì)為線程局部存儲(chǔ)創(chuàng)建一個(gè)新鍵key,根據(jù)key去設(shè)置和獲取數(shù)據(jù)叶骨,參數(shù) destructor 是一個(gè)

自定義函數(shù)指針茫多,void*destructor(void* value){ ? /*多是為了釋放 value 指針指向的資源*/} ,線程終止時(shí)忽刽,如果 key 關(guān)聯(lián)的值不是 NULL地梨,那么 NTPL 會(huì)自動(dòng)執(zhí)行定義的 destructor 函數(shù);

如果無須解構(gòu)缔恳,可以將 destructor 設(shè)置為 NULL宝剖,函數(shù)返回非0表示創(chuàng)建失敗

? ? ? ? ? ? ? ? ? ?? int ? ? pthread_key_delete(pthread_key_t key); //釋放key存儲(chǔ)區(qū)域

? ? ? ? ? ? ? ? ? ?? int ? ? pthread_setspecific(pthread_key_t key,const void*value); //使用Key 設(shè)置存儲(chǔ)數(shù)據(jù)

? ? ? ? ? ? ? ? ? ?? void* pthread_getspecific(pthread_key_t key); //使用key獲得存儲(chǔ)數(shù)據(jù)

? ? ? ? ? ? ? ? ?? 如圖所示,五個(gè)線程 記錄槽位分配情況的數(shù)據(jù)結(jié)構(gòu) pthread_keys 是進(jìn)程唯一的歉甚,pthread_keys 結(jié)構(gòu)示意圖如下:

結(jié)構(gòu)圖

? ? ? ? ?? 此外也和windows一樣提供方法定于線程局部變量:__thread int val = 0;

? ? ? ? ?? 3. C++ 11 標(biāo)準(zhǔn)提供了一個(gè)新的關(guān)鍵字 thread_local 來定義一個(gè)線程變量万细,可兼容windows和linux運(yùn)行,如 : thread_local int g_mydata = 1; 但需要注意的是纸泄,此關(guān)鍵字需要在

Visual Studio 2015 及以上版本才能支持赖钞。

(3)C庫的非線程安全函數(shù):最初編寫很多 CRT 函數(shù)時(shí),還沒有多線程技術(shù)聘裁,很多函數(shù)內(nèi)部實(shí)現(xiàn)都使用了函數(shù)內(nèi)部的靜態(tài)變量和全局變量雪营。隨著多線程技術(shù)的出現(xiàn),很多函數(shù)出現(xiàn)

了對應(yīng)的多線程安全版本衡便,如localtime-> localtime_r献起、strtok->strtok_r,在這些函數(shù)內(nèi)部很多改用了線程局部存儲(chǔ) 技術(shù)來替代原來使用靜態(tài)變量或者全局變量的做法,所以應(yīng)當(dāng)使用多線程

安全版本函數(shù)替換非線程安全版本函數(shù)。

(4)線程池和隊(duì)列系統(tǒng)的設(shè)計(jì):線程池是一組線程的集合镣陕,當(dāng)程序異步執(zhí)行一些任務(wù)時(shí)谴餐,任務(wù)產(chǎn)生和執(zhí)行是貫穿程序整個(gè)生命周期的,通常需要?jiǎng)?chuàng)建一組在程序生命周期內(nèi)不會(huì)退出的

線程呆抑,為了不浪費(fèi)系統(tǒng)資源岂嗓,與其讓操作系統(tǒng)頻繁地創(chuàng)建和銷毀線程,不如由程序根據(jù)任務(wù)的生產(chǎn)消費(fèi)決定線程的休眠和喚醒鹊碍,因此出現(xiàn)線程池的概念厌殉。在程序生命周期會(huì)有多個(gè)任務(wù)食绿,

任務(wù)存放的地方即為隊(duì)列,此處并不簡單指向一個(gè)list公罕,以是一個(gè)全局變量炫欺、鏈表等,隊(duì)列可以先進(jìn)先出熏兄,單向存儲(chǔ)或者循環(huán)存儲(chǔ),涉及數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)不多描述树姨,隊(duì)列是線程的公共資

源摩桶,多個(gè)線程同時(shí)操作這個(gè)隊(duì)列一般需要加鎖。技術(shù)上除了要解決線程池的創(chuàng)建帽揪、往隊(duì)列中投遞任務(wù)硝清、從隊(duì)列中取任務(wù)處理,還需要做一些善后工作转晰,如線程池的清理芦拿,即如何退出線程

池中的工作線程和清理任務(wù)隊(duì)列。

? ? ? ? ?? 當(dāng)然查邢,隨著技術(shù)的發(fā)展蔗崎,出于復(fù)用和解耦的目的,業(yè)界產(chǎn)生了許多獨(dú)立的隊(duì)列系統(tǒng)扰藕,這些隊(duì)列系統(tǒng)或以一個(gè)獨(dú)立的進(jìn)程運(yùn)行或以支持分布式的一組服務(wù)運(yùn)行缓苛,這種獨(dú)立的隊(duì)

列系統(tǒng)稱之為消息中間件,比如 Kafka邓深、ActiveMQ未桥、RabbitMQ、RocketMQ 等芥备,這些消息中間件在功能上做了豐富的擴(kuò)展冬耿,如消費(fèi)的方式、主備切換萌壳、容災(zāi)容錯(cuò)亦镶,數(shù)據(jù)自動(dòng)備份和過期

數(shù)據(jù)自動(dòng)清理等等,適當(dāng)學(xué)習(xí)使用甚至能了解設(shè)計(jì)思想也是很重要的袱瓮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末染乌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懂讯,更是在濱河造成了極大的恐慌荷憋,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褐望,死亡現(xiàn)場離奇詭異勒庄,居然都是意外死亡串前,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進(jìn)店門实蔽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荡碾,“玉大人,你說我怎么就攤上這事局装√秤酰” “怎么了?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵铐尚,是天一觀的道長拨脉。 經(jīng)常有香客問我,道長宣增,這世上最難降的妖魔是什么玫膀? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮爹脾,結(jié)果婚禮上帖旨,老公的妹妹穿的比我還像新娘。我一直安慰自己灵妨,他們只是感情好解阅,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泌霍,像睡著了一般瓮钥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烹吵,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天碉熄,我揣著相機(jī)與錄音,去河邊找鬼肋拔。 笑死锈津,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凉蜂。 我是一名探鬼主播琼梆,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窿吩!你這毒婦竟也來了茎杂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤纫雁,失蹤者是張志新(化名)和其女友劉穎煌往,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轧邪,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刽脖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年羞海,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曲管。...
    茶點(diǎn)故事閱讀 40,926評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡却邓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出院水,到底是詐尸還是另有隱情腊徙,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布檬某,位于F島的核電站撬腾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏橙喘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一胶逢、第九天 我趴在偏房一處隱蔽的房頂上張望厅瞎。 院中可真熱鬧,春花似錦初坠、人聲如沸和簸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锁保。三九已至,卻和暖如春半沽,著一層夾襖步出監(jiān)牢的瞬間爽柒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工者填, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浩村,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓占哟,卻偏偏與公主長得像心墅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子榨乎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 引用自多線程編程指南應(yīng)用程序里面多個(gè)線程的存在引發(fā)了多個(gè)執(zhí)行線程安全訪問資源的潛在問題怎燥。兩個(gè)線程同時(shí)修改同一資源有...
    Mitchell閱讀 2,003評論 1 7
  • pthread 是 POSIX 多線程開發(fā)框架,是跨平臺(tái)的 C 語言框架,需要自己管理線程的創(chuàng)建銷毀等操作蜜暑。 pt...
    有夢想的狼閱讀 1,007評論 0 2
  • 簡介 線程創(chuàng)建 線程屬性設(shè)置 線程參數(shù)傳遞 線程優(yōu)先級(jí) 線程的數(shù)據(jù)處理 線程的分離狀態(tài) 互斥鎖 信號(hào)量 一 線程創(chuàng)...
    第八區(qū)閱讀 8,567評論 1 6
  • Linux/UNIX系統(tǒng)編程手冊 [德] Michael Kerrisk 第29章 線程:介紹第30章 線程:線程...
    妖小灰閱讀 605評論 0 0
  • 概述 線程和進(jìn)程本質(zhì)上來說都屬于一個(gè)內(nèi)核調(diào)度單元懂从,也就是說都可以作為一條單獨(dú)的執(zhí)行路徑。但是多進(jìn)程程序通常有一些限...
    loopppp閱讀 465評論 0 0