日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux下實現(xiàn)高效多核并發(fā)編程技巧(linux多核并發(fā)編程)

隨著計算機硬件的不斷發(fā)展,多核處理器已成為主流,因而多核并發(fā)編程的重要性也得到了進一步的提升。對于Linux系統(tǒng)而言,其作為一個以多用戶、多任務(wù)為特點的操作系統(tǒng),自然而然地也需要支持多核并發(fā)編程。本文就是基于這一背景,介紹一些Linux下實現(xiàn)高效多核并發(fā)編程的技巧。

伊通ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!

1、線程模型

在Linux下實現(xiàn)高效多核并發(fā)編程的之一步,就是選擇適當(dāng)?shù)木€程模型。線程模型是指用于實現(xiàn)并發(fā)編程的線程庫和編程模型。目前常見的線程模型有兩種,分別為用戶空間線程和內(nèi)核空間線程。

用戶空間線程是指基于用戶空間的線程庫,它的優(yōu)勢在于創(chuàng)建線程的開銷較小,但其缺陷在于不能利用操作系統(tǒng)的多核優(yōu)勢,因為它不能綁定到處理器核心上,也就不能實現(xiàn)多核并發(fā)。相比之下,內(nèi)核空間線程則是基于操作系統(tǒng)內(nèi)核的線程庫,它的優(yōu)勢在于可以實現(xiàn)真正的多核并發(fā),但其缺陷在于創(chuàng)建線程的開銷較大。

因此,在選擇線程模型時,需要根據(jù)實際需求來進行選擇。如果程序中線程數(shù)較少,可以使用用戶空間線程;而如果線程數(shù)較多,需要實現(xiàn)真正的多核并發(fā),就應(yīng)選擇內(nèi)核空間線程。

2、任務(wù)調(diào)度

在Linux系統(tǒng)中,任務(wù)調(diào)度是實現(xiàn)多核并發(fā)的基礎(chǔ)。任務(wù)調(diào)度是指操作系統(tǒng)將處理器核心分配給不同的任務(wù)或線程的過程。Linux操作系統(tǒng)是用時間片輪轉(zhuǎn)算法來實現(xiàn)任務(wù)調(diào)度的,在多核處理器下,每個處理器核心都會運行一個調(diào)度器,因此,需要實現(xiàn)良好的任務(wù)調(diào)度策略,才能充分利用多核。

一種常見的任務(wù)調(diào)度策略是將任務(wù)分配到不同的處理器核心上,以實現(xiàn)真正的并發(fā)。在Linux系統(tǒng)中,可以使用taskset命令來設(shè)置任務(wù)的CPU親和性,從而將其綁定到指定的處理器核心上。這樣,不同的任務(wù)會被分配到不同的處理器核心上運行,從而實現(xiàn)真正的并發(fā)。

除了將任務(wù)分配到不同的處理器核心上,還可以使用加鎖和降低線程優(yōu)先級等策略來防止多核并發(fā)下的數(shù)據(jù)競爭和資源爭奪,從而提高程序的并發(fā)性。

3、優(yōu)化程序

為了進一步提高多核并發(fā)程序的效率,需要對程序進行優(yōu)化。常見的程序優(yōu)化方法包括分離任務(wù)和數(shù)據(jù),使用異步IO等。

分離任務(wù)和數(shù)據(jù)是指將任務(wù)和數(shù)據(jù)分別存儲在不同的內(nèi)存中,從而避免多線程同時訪問相同的內(nèi)存區(qū)域,造成資源爭奪和競爭。使用異步IO則是指在提高I/O性能的同時,避免對線程的阻塞。

此外,還可以使用OpenMP等并行編程框架來加速程序,提高并發(fā)性能。例如,使用OpenMP可以將循環(huán)語句并行化,從而充分利用多核處理器的優(yōu)勢,提高程序運行速度。

4、性能分析和調(diào)試

在實現(xiàn)多核并發(fā)編程時,還需要進行性能分析和調(diào)試,以優(yōu)化程序性能和解決問題。常用的性能分析工具包括perf、gprof、valgrind等,它們可以幫助開發(fā)者快速定位程序性能瓶頸和問題所在。在進行性能分析時,需要注意同時監(jiān)控CPU使用率、內(nèi)存使用率、IO使用率等指標(biāo)。

Linux下實現(xiàn)高效多核并發(fā)編程需要綜合考慮線程模型、任務(wù)調(diào)度、程序優(yōu)化、性能分析等多個方面,以充分利用多核處理器的優(yōu)勢,實現(xiàn)高效的并發(fā)編程。作為開發(fā)者,需要了解并掌握這些技巧,以提高程序性能和開發(fā)效率。

成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián)為您提供網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁設(shè)計及定制高端網(wǎng)站建設(shè)服務(wù)!

linux tcp socket并發(fā)編程,調(diào)用accept函數(shù)后調(diào)用fork。兩臺電腦測試,為何accept返回的描述符是相同的?

返回的描述符是當(dāng)前可用的最小描述符,你測試環(huán)境下的兩臺電腦可用的最小描述符是一樣的。

可能是你的fork 之后產(chǎn)生的子進程拷貝的代碼,它那里執(zhí)行了accept,所以導(dǎo)致相跡臘攔同,你試著在每個fork之后的函數(shù)中用個exit(1);將子進程退出,然后應(yīng)該就不會有這個問姿胡題了局坦。

如何實現(xiàn)linux下多線程之間的互斥與同步

Linux設(shè)備驅(qū)動中必須解決的一個問題是多個進程對共享資源的并發(fā)訪問,并發(fā)訪問會導(dǎo)致競態(tài),linux提供了多種解決競態(tài)問題的方式,這些方式適合不同的應(yīng)用場景。

Linux內(nèi)核是多進程、多線程的操作系統(tǒng),它提供了相當(dāng)完整的內(nèi)核同步方法。內(nèi)核同步方法列表如下:

中斷屏蔽

原子操作

自旋鎖

讀寫自旋鎖

順序鎖

信號量

讀寫信號量

BKL(大內(nèi)核鎖)

Seq鎖

一、并發(fā)與競態(tài):

定義:

并發(fā)(concurrency)指的是多個執(zhí)行單元同時、并行被執(zhí)行,而并發(fā)的執(zhí)行單元對共享資源(硬件資源和軟件上的全局變量、靜態(tài)變量等)的訪問則很容易導(dǎo)致競態(tài)(race conditions)。

在linux中,主要的競態(tài)發(fā)生在如下幾種情況:

1、對稱多處理器歷辯埋(P)多個CPU

特點是多個CPU使用共同的系統(tǒng)總線,因此可訪問共同的外設(shè)和存儲器。

2、單CPU內(nèi)進程與搶占它的進程

3、中斷(硬中斷、軟中斷、Tasklet、底半部)與進程之間

只要并發(fā)的多個執(zhí)行單元存在對共享資源的訪問,競態(tài)就有可能發(fā)生。

如果中斷處理程序訪問進程正在訪問的資源,則競態(tài)也會會發(fā)生。

多個中斷之間本身也可能引起并發(fā)而導(dǎo)致競態(tài)(中斷被更高優(yōu)先級的中斷打斷)。

解決競態(tài)問題的途徑是保證對共享資源的互斥訪問,所謂互斥訪問就是指一個執(zhí)行單元在訪問共享資源的時候,其他的執(zhí)行單元都被禁止訪問。

訪問共享資源的代碼區(qū)域被稱為臨界區(qū),臨界區(qū)需要以某種互斥機制加以保護,中斷屏蔽,原子操作,自旋鎖,和信號量都是linux設(shè)備驅(qū)動中可采用的互斥途徑。

臨界區(qū)和競爭條件:

所謂臨界區(qū)(critical regions)就是訪問和操作共享數(shù)據(jù)的代碼段,為了避免在臨界區(qū)中并發(fā)訪問,編程者必須保證這些代碼原子地執(zhí)行——也就是說,代碼在執(zhí)行結(jié)束前不可被打斷,就如同整個臨界區(qū)是一個不可分割的指令一樣,如果兩個執(zhí)行線程有可能處于同一個臨界區(qū)中,那么就是程序包含一個bug,如果這種情況發(fā)生了,我們就稱之為競爭條件(race conditions),避免并發(fā)和防止競爭條件被稱為同步。

死鎖:

死鎖的產(chǎn)生需要一定條件:要有一個或多個執(zhí)行線程和一個或多個資源,每個線程都在等待其中的一個資源,但所有的資源都已經(jīng)被占用了,所有線程都在相互等待,但它們永遠(yuǎn)不會釋放已經(jīng)占有的資源,于是任何線程都無法繼續(xù),這便意味著死鎖的發(fā)生。

二、中斷屏蔽

在單CPU范圍內(nèi)避免競態(tài)的一種簡單方法是在進入臨界區(qū)之前屏蔽系統(tǒng)的中斷。

由于linux內(nèi)核的進程調(diào)度等操作都依賴中斷來實現(xiàn),內(nèi)核搶占進程之間的并發(fā)也就得以避免了。

中斷屏蔽的使用方法:

local_irq_disable()//屏蔽中斷

//臨界區(qū)

local_irq_enable()//灶念開中斷

特點:

由于linux系統(tǒng)的異步IO,進程調(diào)度等很多重要操作都依賴于中斷,在屏蔽中斷期間所有的中斷都無法得到處理,因此長時間的屏蔽是很危險的,有可能造成數(shù)據(jù)丟失甚至系統(tǒng)崩潰,這就要求在屏蔽中斷之后,當(dāng)前的內(nèi)核執(zhí)行路徑應(yīng)當(dāng)盡快地執(zhí)行完臨界區(qū)的代碼。

中斷屏蔽只能禁止本CPU內(nèi)的中斷,因此,并不能解決多CPU引發(fā)的競態(tài),所以單獨使用中斷屏蔽并不是一個值得推薦的避免競態(tài)的方法,它一般和自旋鎖配合使用。

三、原子操作

定義:原子操作指的是在執(zhí)行過程中不會被別的代碼路徑所中斷的操作。

(原子原本指的是不可分割的微粒,所以原子操作也就是不能夠被分割的指令)

(它保證指令以“原子”的方式執(zhí)行而不能被打斷)

原子操作是不可分割的,在執(zhí)行完畢不會被任何其它任務(wù)或事件中斷。在單處理器系統(tǒng)(UniProcessor)中,能夠在單條指令中完成的操作都可以認(rèn)為是” 原子操作”,因為中斷只能發(fā)生于指令之間。這也是某些CPU指令系統(tǒng)中引入了test_and_set、test_and_clear等指令用于臨界資源互斥的原因。但是,在對稱多處理器(Symmetric Multi-Processor)結(jié)構(gòu)中就不同了,由于系統(tǒng)中有多個處理器在獨立地運行,即使能在單條指令中完成的操作也有可能受到干擾。我們以decl (遞減指令)為例,這是一個典型的”讀-改-肢螞寫”過程,涉及兩次內(nèi)存訪問。

通俗理解:

原子操作,顧名思義,就是說像原子一樣不可再細(xì)分。一個操作是原子操作,意思就是說這個操作是以原子的方式被執(zhí)行,要一口氣執(zhí)行完,執(zhí)行過程不能夠被OS的其他行為打斷,是一個整體的過程,在其執(zhí)行過程中,OS的其它行為是插不進來的。

分類:linux內(nèi)核提供了一系列函數(shù)來實現(xiàn)內(nèi)核中的原子操作,分為整型原子操作和位原子操作,共同點是:在任何情況下操作都是原子的,內(nèi)核代碼可以安全的調(diào)用它們而不被打斷。

原子整數(shù)操作:

針對整數(shù)的原子操作只能對atomic_t類型的數(shù)據(jù)進行處理,在這里之所以引入了一個特殊的數(shù)據(jù)類型,而沒有直接使用C語言的int型,主要是出于兩個原因:

之一、讓原子函數(shù)只接受atomic_t類型的操作數(shù),可以確保原子操作只與這種特殊類型數(shù)據(jù)一起使用,同時,這也確保了該類型的數(shù)據(jù)不會被傳遞給其它任何非原子函數(shù);

第二、使用atomic_t類型確保編譯器不對相應(yīng)的值進行訪問優(yōu)化——這點使得原子操作最終接收到正確的內(nèi)存地址,而不是一個別名,最后就是在不同體系結(jié)構(gòu)上實現(xiàn)原子操作的時候,使用atomic_t可以屏蔽其間的差異。

原子整數(shù)操作最常見的用途就是實現(xiàn)計數(shù)器。

另一點需要說明原子操作只能保證操作是原子的,要么完成,要么不完成,不會有操作一半的可能,但原子操作并不能保證操作的順序性,即它不能保證兩個操作是按某個順序完成的。如果要保證原子操作的順序性,請使用內(nèi)存屏障指令。

atomic_t和ATOMIC_INIT(i)定義

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i) { (i) }

在你編寫代碼的時候,能使用原子操作的時候,就盡量不要使用復(fù)雜的加鎖機制,對多數(shù)體系結(jié)構(gòu)來講,原子操作與更復(fù)雜的同步方法相比較,給系統(tǒng)帶來的開銷小,對高速緩存行的影響也小,但是,對于那些有高性能要求的代碼,對多種同步方法進行測試比較,不失為一種明智的作法。

原子位操作:

針對位這一級數(shù)據(jù)進行操作的函數(shù),是對普通的內(nèi)存地址進行操作的。它的參數(shù)是一個指針和一個位號。

為方便其間,內(nèi)核還提供了一組與上述操作對應(yīng)的非原子位函數(shù),非原子位函數(shù)與原子位函數(shù)的操作完全相同,但是,前者不保證原子性,且其名字前綴多兩個下劃線。例如,與test_bit()對應(yīng)的非原子形式是_test_bit(),如果你不需要原子性操作(比如,如果你已經(jīng)用鎖保護了自己的數(shù)據(jù)),那么這些非原子的位函數(shù)相比原子的位函數(shù)可能會執(zhí)行得更快些。

四、自旋鎖

自旋鎖的引入:

如 果每個臨界區(qū)都能像增加變量這樣簡單就好了,可惜現(xiàn)實不是這樣,而是臨界區(qū)可以跨越多個函數(shù),例如:先得從一個數(shù)據(jù)結(jié)果中移出數(shù)據(jù),對其進行格式轉(zhuǎn)換和解 析,最后再把它加入到另一個數(shù)據(jù)結(jié)構(gòu)中,整個執(zhí)行過程必須是原子的,在數(shù)據(jù)被更新完畢之前,不能有其他代碼讀取這些數(shù)據(jù),顯然,簡單的原子操作是無能為力 的(在單處理器系統(tǒng)(UniProcessor)中,能夠在單條指令中完成的操作都可以認(rèn)為是” 原子操作”,因為中斷只能發(fā)生于指令之間),這就需要使用更為復(fù)雜的同步方法——鎖來提供保護。

自旋鎖的介紹:

Linux內(nèi)核中最常見的鎖是自旋鎖(spin lock),自旋鎖最多只能被一個可執(zhí)行線程持有,如果一個執(zhí)行線程試圖獲得一個被爭用(已經(jīng)被持有)的自旋鎖,那么該線程就會一直進行忙循環(huán)—旋轉(zhuǎn)—等待鎖重新可用,要是鎖未被爭用,請求鎖的執(zhí)行線程便能立刻得到它,繼續(xù)執(zhí)行,在任意時間,自旋鎖都可以防止多于一個的執(zhí)行線程同時進入理解區(qū),注意同一個鎖可以用在多個位置—例如,對于給定數(shù)據(jù)的所有訪問都可以得到保護和同步。

一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時自旋(特別浪費處理器時間),所以自旋鎖不應(yīng)該被長時間持有,事實上,這點正是使用自旋鎖的初衷,在短期間內(nèi)進行輕量級加鎖,還可以采取另外的方式來處理對鎖的爭用:讓請求線程睡眠,直到鎖重新可用時再喚醒它,這樣處理器就不必循環(huán)等待,可以去執(zhí)行其他代碼,這也會帶來一定的開銷——這里有兩次明顯的上下文切換, 被阻塞的線程要換出和換入。因此,持有自旋鎖的時間更好小于完成兩次上下文切換的耗時,當(dāng)然我們大多數(shù)人不會無聊到去測量上下文切換的耗時,所以我們讓持 有自旋鎖的時間應(yīng)盡可能的短就可以了,信號量可以提供上述第二種機制,它使得在發(fā)生爭用時,等待的線程能投入睡眠,而不是旋轉(zhuǎn)。

自旋鎖可以使用在中斷處理程序中(此處不能使用信號量,因為它們會導(dǎo)致睡眠),在中斷處理程序中使用自旋鎖時,一定要在獲取鎖之前,首先禁止本地中斷(在 當(dāng)前處理器上的中斷請求),否則,中斷處理程序就會打斷正持有鎖的內(nèi)核代碼,有可能會試圖去爭用這個已經(jīng)持有的自旋鎖,這樣以來,中斷處理程序就會自旋, 等待該鎖重新可用,但是鎖的持有者在這個中斷處理程序執(zhí)行完畢前不可能運行,這正是我們在前一章節(jié)中提到的雙重請求死鎖,注意,需要關(guān)閉的只是當(dāng)前處理器上的中斷,如果中斷發(fā)生在不同的處理器上,即使中斷處理程序在同一鎖上自旋,也不會妨礙鎖的持有者(在不同處理器上)最終釋放鎖。

自旋鎖的簡單理解:

理解自旋鎖最簡單的方法是把它作為一個變量看待,該變量把一個臨界區(qū)或者標(biāo)記為“我當(dāng)前正在運行,請稍等一會”或者標(biāo)記為“我當(dāng)前不在運行,可以被使用”。如果A執(zhí)行單元首先進入例程,它將持有自旋鎖,當(dāng)B執(zhí)行單元試圖進入同一個例程時,將獲知自旋鎖已被持有,需等到A執(zhí)行單元釋放后才能進入。

自旋鎖的API函數(shù):

其實介紹的幾種信號量和互斥機制,其底層源碼都是使用自旋鎖,可以理解為自旋鎖的再包裝。所以從這里就可以理解為什么自旋鎖通??梢蕴峁┍刃盘柫扛叩男阅?。

自旋鎖是一個互斥設(shè)備,他只能會兩個值:“鎖定”和“解鎖”。它通常實現(xiàn)為某個整數(shù)之中的單個位。

“測試并設(shè)置”的操作必須以原子方式完成。

任何時候,只要內(nèi)核代碼擁有自旋鎖,在相關(guān)CPU上的搶占就會被禁止。

適用于自旋鎖的核心規(guī)則:

(1)任何擁有自旋鎖的代碼都必須使原子的,除服務(wù)中斷外(某些情況下也不能放棄CPU,如中斷服務(wù)也要獲得自旋鎖。為了避免這種鎖陷阱,需要在擁有自旋鎖時禁止中斷),不能放棄CPU(如休眠,休眠可發(fā)生在許多無法預(yù)期的地方)。否則CPU將有可能永遠(yuǎn)自旋下去(死機)。

(2)擁有自旋鎖的時間越短越好。

需 要強調(diào)的是,自旋鎖別設(shè)計用于多處理器的同步機制,對于單處理器(對于單處理器并且不可搶占的內(nèi)核來說,自旋鎖什么也不作),內(nèi)核在編譯時不會引入自旋鎖 機制,對于可搶占的內(nèi)核,它僅僅被用于設(shè)置內(nèi)核的搶占機制是否開啟的一個開關(guān),也就是說加鎖和解鎖實際變成了禁止或開啟內(nèi)核搶占功能。如果內(nèi)核不支持搶 占,那么自旋鎖根本就不會編譯到內(nèi)核中。

內(nèi)核中使用spinlock_t類型來表示自旋鎖,它定義在:

typedef struct {

raw_spinlock_t raw_lock;

#if defined(CONFIG_PREEMPT) && defined(CONFIG_P)

unsigned int break_lock;

#endif

} spinlock_t;

對于不支持P的內(nèi)核來說,struct raw_spinlock_t什么也沒有,是一個空結(jié)構(gòu)。對于支持多處理器的內(nèi)核來說,struct raw_spinlock_t定義為

typedef struct {

unsigned int slock;

} raw_spinlock_t;

slock表示了自旋鎖的狀態(tài),“1”表示自旋鎖處于解鎖狀態(tài)(UNLOCK),“0”表示自旋鎖處于上鎖狀態(tài)(LOCKED)。

break_lock表示當(dāng)前是否由進程在等待自旋鎖,顯然,它只有在支持搶占的P內(nèi)核上才起作用。

自旋鎖的實現(xiàn)是一個復(fù)雜的過程,說它復(fù)雜不是因為需要多少代碼或邏輯來實現(xiàn)它,其實它的實現(xiàn)代碼很少。自旋鎖的實現(xiàn)跟體系結(jié)構(gòu)關(guān)系密切,核心代碼基本也是由匯編語言寫成,與體協(xié)結(jié)構(gòu)相關(guān)的核心代碼都放在相關(guān)的目錄下,比如。對于我們驅(qū)動程序開發(fā)人員來說,我們沒有必要了解這么spinlock的內(nèi)部細(xì)節(jié),如果你對它感興趣,請參考閱讀Linux內(nèi)核源代碼。對于我們驅(qū)動的spinlock接口,我們只需包括頭文件。在我們詳細(xì)的介紹spinlock的API之前,我們先來看看自旋鎖的一個基本使用格式:

#include

spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock(&lock);

….

spin_unlock(&lock);

從使用上來說,spinlock的API還很簡單的,一般我們會用的的API如下表,其實它們都是定義在中的宏接口,真正的實現(xiàn)在中

#include

SPIN_LOCK_UNLOCKED

DEFINE_SPINLOCK

spin_lock_init( spinlock_t *)

spin_lock(spinlock_t *)

spin_unlock(spinlock_t *)

spin_lock_irq(spinlock_t *)

spin_unlock_irq(spinlock_t *)

spin_lock_irqsace(spinlock_t *,unsigned long flags)

spin_unlock_irqsace(spinlock_t *, unsigned long flags)

spin_trylock(spinlock_t *)

spin_is_locked(spinlock_t *)

? 初始化

spinlock有兩種初始化形式,一種是靜態(tài)初始化,一種是動態(tài)初始化。對于靜態(tài)的spinlock對象,我們用 SPIN_LOCK_UNLOCKED來初始化,它是一個宏。當(dāng)然,我們也可以把聲明spinlock和初始化它放在一起做,這就是 DEFINE_SPINLOCK宏的工作,因此,下面的兩行代碼是等價的。

DEFINE_SPINLOCK (lock);

spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock_init 函數(shù)一般用來初始化動態(tài)創(chuàng)建的spinlock_t對象,它的參數(shù)是一個指向spinlock_t對象的指針。當(dāng)然,它也可以初始化一個靜態(tài)的沒有初始化的spinlock_t對象。

spinlock_t *lock

……

spin_lock_init(lock);

? 獲取鎖

內(nèi)核提供了三個函數(shù)用于獲取一個自旋鎖。

spin_lock:獲取指定的自旋鎖。

spin_lock_irq:禁止本地中斷并獲取自旋鎖。

spin_lock_irqsace:保存本地中斷狀態(tài),禁止本地中斷并獲取自旋鎖,返回本地中斷狀態(tài)。

自旋鎖是可以使用在中斷處理程序中的,這時需要使用具有關(guān)閉本地中斷功能的函數(shù),我們推薦使用 spin_lock_irqsave,因為它會保存加鎖前的中斷標(biāo)志,這樣就會正確恢復(fù)解鎖時的中斷標(biāo)志。如果spin_lock_irq在加鎖時中斷是關(guān)閉的,那么在解鎖時就會錯誤的開啟中斷。

另外兩個同自旋鎖獲取相關(guān)的函數(shù)是:

spin_trylock():嘗試獲取自旋鎖,如果獲取失敗則立即返回非0值,否則返回0。

spin_is_locked():判斷指定的自旋鎖是否已經(jīng)被獲取了。如果是則返回非0,否則,返回0。

? 釋放鎖

同獲取鎖相對應(yīng),內(nèi)核提供了三個相對的函數(shù)來釋放自旋鎖。

spin_unlock:釋放指定的自旋鎖。

spin_unlock_irq:釋放自旋鎖并激活本地中斷。

spin_unlock_irqsave:釋放自旋鎖,并恢復(fù)保存的本地中斷狀態(tài)。

五、讀寫自旋鎖

如 果臨界區(qū)保護的數(shù)據(jù)是可讀可寫的,那么只要沒有寫操作,對于讀是可以支持并發(fā)操作的。對于這種只要求寫操作是互斥的需求,如果還是使用自旋鎖顯然是無法滿 足這個要求(對于讀操作實在是太浪費了)。為此內(nèi)核提供了另一種鎖-讀寫自旋鎖,讀自旋鎖也叫共享自旋鎖,寫自旋鎖也叫排他自旋鎖。

讀寫自旋鎖是一種比自旋鎖粒度更小的鎖機制,它保留了“自旋”的概念,但是在寫操作方面,只能最多有一個寫進程,在讀操作方面,同時可以有多個讀執(zhí)行單元,當(dāng)然,讀和寫也不能同時進行。

讀寫自旋鎖的使用也普通自旋鎖的使用很類似,首先要初始化讀寫自旋鎖對象:

// 靜態(tài)初始化

rwlock_t rwlock = RW_LOCK_UNLOCKED;

//動態(tài)初始化

rwlock_t *rwlock;

rw_lock_init(rwlock);

在讀操作代碼里對共享數(shù)據(jù)獲取讀自旋鎖:

read_lock(&rwlock);

read_unlock(&rwlock);

在寫操作代碼里為共享數(shù)據(jù)獲取寫自旋鎖:

write_lock(&rwlock);

write_unlock(&rwlock);

需要注意的是,如果有大量的寫操作,會使寫操作自旋在寫自旋鎖上而處于寫?zhàn)囸I狀態(tài)(等待讀自旋鎖的全部釋放),因為讀自旋鎖會自由的獲取讀自旋鎖。

讀寫自旋鎖的函數(shù)類似于普通自旋鎖,這里就不一一介紹了,我們把它列在下面的表中。

RW_LOCK_UNLOCKED

rw_lock_init(rwlock_t *)

read_lock(rwlock_t *)

read_unlock(rwlock_t *)

read_lock_irq(rwlock_t *)

read_unlock_irq(rwlock_t *)

read_lock_irqsave(rwlock_t *, unsigned long)

read_unlock_irqsave(rwlock_t *, unsigned long)

write_lock(rwlock_t *)

write_unlock(rwlock_t *)

write_lock_irq(rwlock_t *)

write_unlock_irq(rwlock_t *)

write_lock_irqsave(rwlock_t *, unsigned long)

write_unlock_irqsave(rwlock_t *, unsigned long)

rw_is_locked(rwlock_t *)

六、順序瑣

順序瑣(seqlock)是對讀寫鎖的一種優(yōu)化,若使用順序瑣,讀執(zhí)行單元絕不會被寫執(zhí)行單元阻塞,也就是說,讀執(zhí)行單元可以在寫執(zhí)行單元對被順序瑣保護的共享資源進行寫操作時仍然可以繼續(xù)讀,而不必等待寫執(zhí)行單元完成寫操作,寫執(zhí)行單元也不需要等待所有讀執(zhí)行單元完成讀操作才去進行寫操作。

但是,寫執(zhí)行單元與寫執(zhí)行單元之間仍然是互斥的,即如果有寫執(zhí)行單元在進行寫操作,其它寫執(zhí)行單元必須自旋在哪里,直到寫執(zhí)行單元釋放了順序瑣。

如果讀執(zhí)行單元在讀操作期間,寫執(zhí)行單元已經(jīng)發(fā)生了寫操作,那么,讀執(zhí)行單元必須重新讀取數(shù)據(jù),以便確保得到的數(shù)據(jù)是完整的,這種鎖在讀寫同時進行的概率比較小時,性能是非常好的,而且它允許讀寫同時進行,因而更大的提高了并發(fā)性,

注意,順序瑣由一個限制,就是它必須被保護的共享資源不含有指針,因為寫執(zhí)行單元可能使得指針失效,但讀執(zhí)行單元如果正要訪問該指針,將導(dǎo)致Oops。

七、信號量

Linux中的信號量是一種睡眠鎖,如果有一個任務(wù)試圖獲得一個已經(jīng)被占用的信號量時,信號量會將其推進一個等待隊列,然后讓其睡眠,這時處理器能重獲自由,從而去執(zhí)行其它代碼,當(dāng)持有信號量的進程將信號量釋放后,處于等待隊列中的哪個任務(wù)被喚醒,并獲得該信號量。

信號量,或旗標(biāo),就是我們在操作系統(tǒng)里學(xué)習(xí)的經(jīng)典的P/V原語操作。

P:如果信號量值大于0,則遞減信號量的值,程序繼續(xù)執(zhí)行,否則,睡眠等待信號量大于0。

V:遞增信號量的值,如果遞增的信號量的值大于0,則喚醒等待的進程。

信號量的值確定了同時可以有多少個進程可以同時進入臨界區(qū),如果信號量的初始值始1,這信號量就是互斥信號量(MUTEX)。對于大于1的非0值信號量,也可稱為計數(shù)信號量(counting semaphore)。對于一般的驅(qū)動程序使用的信號量都是互斥信號量。

類似于自旋鎖,信號量的實現(xiàn)也與體系結(jié)構(gòu)密切相關(guān),具體的實現(xiàn)定義在頭文件中,對于x86_32系統(tǒng)來說,它的定義如下:

struct semaphore {

atomic_t count;

int sleepers;

wait_queue_head_t wait;

};

信號量的初始值count是atomic_t類型的,這是一個原子操作類型,它也是一個內(nèi)核同步技術(shù),可見信號量是基于原子操作的。我們會在后面原子操作部分對原子操作做詳細(xì)介紹。

信號量的使用類似于自旋鎖,包括創(chuàng)建、獲取和釋放。我們還是來先展示信號量的基本使用形式:

static DECLARE_MUTEX(my_sem);

……

if (down_interruptible(&my_sem))

{

return -ERESTARTSYS;

}

……

up(&my_sem)

Linux內(nèi)核中的信號量函數(shù)接口如下:

static DECLARE_SEMAPHORE_GENERIC(name, count);

static DECLARE_MUTEX(name);

seam_init(struct semaphore *, int);

init_MUTEX(struct semaphore *);

init_MUTEX_LOCKED(struct semaphore *)

down_interruptible(struct semaphore *);

down(struct semaphore *)

down_trylock(struct semaphore *)

up(struct semaphore *)

? 初始化信號量

信號量的初始化包括靜態(tài)初始化和動態(tài)初始化。靜態(tài)初始化用于靜態(tài)的聲明并初始化信號量。

static DECLARE_SEMAPHORE_GENERIC(name, count);

static DECLARE_MUTEX(name);

對于動態(tài)聲明或創(chuàng)建的信號量,可以使用如下函數(shù)進行初始化:

seam_init(sem, count);

init_MUTEX(sem);

init_MUTEX_LOCKED(struct semaphore *)

顯然,帶有MUTEX的函數(shù)始初始化互斥信號量。LOCKED則初始化信號量為鎖狀態(tài)。

? 使用信號量

信號量初始化完成后我們就可以使用它了

down_interruptible(struct semaphore *);

down(struct semaphore *)

down_trylock(struct semaphore *)

up(struct semaphore *)

down函數(shù)會嘗試獲取指定的信號量,如果信號量已經(jīng)被使用了,則進程進入不可中斷的睡眠狀態(tài)。down_interruptible則會使進程進入可中斷的睡眠狀態(tài)。關(guān)于進程狀態(tài)的詳細(xì)細(xì)節(jié),我們在內(nèi)核的進程管理里在做詳細(xì)介紹。

down_trylock嘗試獲取信號量, 如果獲取成功則返回0,失敗則會立即返回非0。

當(dāng)退出臨界區(qū)時使用up函數(shù)釋放信號量,如果信號量上的睡眠隊列不為空,則喚醒其中一個等待進程。

八、讀寫信號量

類似于自旋鎖,信號量也有讀寫信號量。讀寫信號量API定義在頭文件中,它的定義其實也是體系結(jié)構(gòu)相關(guān)的,因此具體實現(xiàn)定義在頭文件中,以下是x86的例子:

struct rw_semaphore {

signed long count;

spinlock_t wait_lock;

struct list_head wait_list;

};

Linux開發(fā)需要什么呢??需要具備什么基礎(chǔ)呢??

linux更先要學(xué)的是Linux基礎(chǔ)知識,學(xué)完基礎(chǔ)知識才算入門,之后還要學(xué)習(xí)綜合架構(gòu)、Shell編程、數(shù)據(jù)庫、云計算以及網(wǎng)絡(luò)安全方面的知識,以下是linux基礎(chǔ)部分要學(xué)習(xí)的內(nèi)容:

1. 計算機硬件、組成原理、操作系統(tǒng)基礎(chǔ)、Linux起源、核心介紹及Linux安裝實戰(zhàn)入門

2. Xshell遠(yuǎn)程網(wǎng)絡(luò)連接Linux、基礎(chǔ)優(yōu)化、遠(yuǎn)程連接網(wǎng)絡(luò)基礎(chǔ)納枝爛、Xshell連接故障排錯、核心基礎(chǔ)命令講解

3. Linux系統(tǒng)核心通配符體系、三劍客(grep,sed,awk)核搭賀心正則表達(dá)式精講及企業(yè)級案例實戰(zhàn)模擬精講

4. Bash核心符號、快捷鍵、通配符詳解

5. Linux目錄、FHS\掛載、文件屬性、核心洞漏目錄精講

6. Linux文件及目錄管理核心知識和命令精講(第二關(guān))

7. Linux企業(yè)級基礎(chǔ)優(yōu)化(工作中可直接使用

8. Linux文件及目錄權(quán)限精講及多個企業(yè)案例模擬

9. Linux重要核心命令回顧與深入精講(第三關(guān))

一、linux和os:

1、命令:

netstat tcpdump ipcs ipcrm 這四個命令的熟練掌握程度基本上能體現(xiàn)實際開發(fā)和調(diào)試程序的經(jīng)驗

2、cpu 內(nèi)存 硬盤 等等與系統(tǒng)性能調(diào)試相關(guān)的命令

必須熟練掌握,設(shè)置修改權(quán)限 tcp網(wǎng)絡(luò)狀態(tài)查看 各進程狀春枝燃態(tài) 抓包相關(guān)等相關(guān)命令 必須熟練掌握

3、awk sed需掌握

4、共享內(nèi)存的使用實現(xiàn)原理、然后共享內(nèi)存段被映射進進程空間之后,存在于進程空間的什么位置?共享內(nèi)存段更大限制是多少?

5、c++

進程內(nèi)存空間分布(注意各部分的內(nèi)存地址誰高誰低,注意棧從高道低分配,堆從低到高分配)

6、ELF是什么?

其大小與程序中全局變量的是否初始化有什么關(guān)系(注意.bss段)

7、

使用過哪些進程間通訊機制,并詳細(xì)說明

8、makefile編寫

,雖然比較基礎(chǔ),但是會被問到

9、gdb

調(diào)試相關(guān)的經(jīng)驗,會被問到

10、如何定位內(nèi)存泄露?

11、動態(tài)鏈接和靜態(tài)鏈接的區(qū)別

12、32位系統(tǒng)一個進程最多多少堆內(nèi)存

13、多線程和多進程的區(qū)別

(重點 必須從cpu調(diào)度,上下文切換,數(shù)據(jù)共享,多核cup利用率,資源占用,等等各方面回答,然后有一個問題必須會被問到:哪些東西是一個線程私有的?答案中必須包含寄存器,否則悲催)

14、

寫一個c程序辨別系統(tǒng)是64位 or 32位

15、

寫一個c程序辨別系統(tǒng)是大端or小端字節(jié)序

16、

信號:列出常見的信號,信號怎么處理?

17、

i++是否原子操作?并解釋為什么???????

18、

說出你所知道的各類linux系統(tǒng)的各類同步機制(重點),扒虛什么是死鎖?如何避免死鎖(每個技術(shù)面試官必問)

19、

列舉說明linux系統(tǒng)的各類異步機制

20、

exit() _exit()的區(qū)別?

21、

如何實現(xiàn)守護進程?

22、

linux的內(nèi)存管理機制是什么?

23、

linux的任務(wù)調(diào)度機制是什么?

24、

標(biāo)準(zhǔn)庫函數(shù)和系統(tǒng)調(diào)用的區(qū)別?

25、

補充一個問題:系統(tǒng)如何將一個信號通知到進程?

二、c語言:

1、宏定義和展開(必須精通)

2、位操作(必須精通)

3、指針操作和計算(必須精通)

4、內(nèi)存分配(必須精通)

5、各類庫函數(shù)必須非常熟練的實現(xiàn)

6、哪些庫函數(shù)屬于高危函數(shù),為什么?(strcpy等等)

三、c++:

1、一個String類的完整實現(xiàn)必須很快速寫出來(注意:賦值構(gòu)造,operator=是關(guān)鍵)

2、虛函數(shù)的作用和實現(xiàn)原理(必問必考,實現(xiàn)原理必須很熟)

3、sizeof一個類求大小(注意成員變量,函數(shù),虛函數(shù),繼承等等對大小的影響)

4、指針和引用的區(qū)別(一般都會問到)

5、多重類構(gòu)造和析構(gòu)的順序

6、stl各容器的實現(xiàn)搭搭原理(必考)

7、extern c 是干啥的,(必須將編譯器的函數(shù)名修飾的機制解答的很透徹)

8、volatile是干啥用的,(必須將cpu的寄存器緩存機制回答的很透徹)

9、static const等等的用法,(能說出越多越好)

四、數(shù)據(jù)結(jié)構(gòu)或者算法:

1、《離散數(shù)學(xué)》范圍內(nèi)的一切問題皆由可能被深入問到(最重要,最體現(xiàn)功底,最能加分,特別是各類樹結(jié)構(gòu)的實現(xiàn)和應(yīng)用)

2、各類排序:大根堆的實現(xiàn),快排(如何避免最糟糕的狀態(tài)?),bitmap的運用等等

3、hash, 任何一個技術(shù)面試官必問(例如為什么一般hashtable的桶數(shù)會取一個素數(shù)?如何有效避免hash結(jié)果值的碰撞)

五、網(wǎng)絡(luò)編程:

1、tcp與udp的區(qū)別(必問)

2、udp調(diào)用connect有什么作用?

3、tcp連接中時序圖,狀態(tài)圖,必須非常非常熟練

4、socket服務(wù)端的實現(xiàn),select和epoll的區(qū)別(必問)

5、epoll哪些觸發(fā)模式,有啥區(qū)別?(必須非常詳盡的解釋水平觸發(fā)和邊緣觸發(fā)的區(qū)別,以及邊緣觸發(fā)在編程中要做哪些更多的確認(rèn))

6、大規(guī)模連接上來,并發(fā)模型怎么設(shè)計

7、tcp結(jié)束連接怎么握手,time_wait狀態(tài)是什么,為什么會有time_wait狀態(tài)?哪一方會有time_wait狀態(tài),如何避免time_wait狀態(tài)占用資源(必須回答的詳細(xì))

8、tcp頭多少字節(jié)?哪些字段?(必問)

9、什么是滑動窗口(必問)

10、connect會阻塞,怎么解決?(必考必問,提示:設(shè)置非阻塞,返回之后用select檢測狀態(tài))

11、如果select返回可讀,結(jié)果只讀到0字節(jié),什么情況?

12、keepalive 是什么東東?如何使用?

13、列舉你所知道的tcp選項,并說明其作用。

14、socket什么情況下可讀?

六、db:

1、mysql,會考sql語言,服務(wù)器數(shù)據(jù)庫大規(guī)模數(shù)據(jù)怎么設(shè)計,db各種性能指標(biāo)

1.掌握基礎(chǔ)旦賣操擾談作命令

2.Linuxshell編程。

重要的是要體系的學(xué)習(xí),模李逗可以報個班什么的。

linux 多核并發(fā)編程的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于linux 多核并發(fā)編程,Linux下實現(xiàn)高效多核并發(fā)編程技巧,linux tcp socket并發(fā)編程,調(diào)用accept函數(shù)后調(diào)用fork。兩臺電腦測試,為何accept返回的描述符是相同的?,如何實現(xiàn)linux下多線程之間的互斥與同步,Linux開發(fā)需要什么呢??需要具備什么基礎(chǔ)呢??的信息別忘了在本站進行查找喔。

創(chuàng)新互聯(lián)(cdcxhl.com)提供穩(wěn)定的云服務(wù)器,香港云服務(wù)器,BGP云服務(wù)器,雙線云服務(wù)器,高防云服務(wù)器,成都云服務(wù)器,服務(wù)器托管。精選鉅惠,歡迎咨詢:028-86922220。


標(biāo)題名稱:Linux下實現(xiàn)高效多核并發(fā)編程技巧(linux多核并發(fā)編程)
文章源于:http://www.dlmjj.cn/article/ccspsed.html