導航:首頁 > 編程知識 > 編程中上下文切換是什麼意思

編程中上下文切換是什麼意思

發布時間:2023-06-01 20:32:34

❶ 如何理解c/c++和php語言的區別

一、編程語言

1.根據熟悉的語言,談談兩種語言的區別?

主要淺談下C/C++和PHP語言的區別:

1)PHP弱類型語言,一種腳本語言,對數據的類型不要求過多,較多的應用於Web應用開發,現在好多互聯網開發公司的主流web後台開發語言,主要框架為mvc模型,如smarty,yaf,升級的PHP7速度較快,對伺服器的壓力要小很多,在新浪微博已經有應用,對比很明顯。

2)C/C++開發語言,C語言更偏向硬體底層開發,C++語言是目前為止我認為語法內容最多的一種語言。C/C++在執行速度上要快很多,畢竟其他類型的語言大都是C開發的,更多應用於網路編程和嵌入式編程。

2.volatile是幹啥用的,(必須將cpu的寄存器緩存機制回答得很透徹),使用實例有哪些?(重點)

1) 訪問寄存器比訪問內存單元要快,編譯器會優化減少內存的讀取,可能會讀臟數據。聲明變數為volatile,編譯器不再對訪問該變數的代碼優化,仍然從內存讀取,使訪問穩定。

總結:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變數表示該變數隨時可能發生變化,與該變數有關的運算,不再編譯優化,以免出錯。

2)使用實例如下( 區分C程序員和嵌入式系統程序員的最基本的問題。 ):

並行設備的硬體寄存器(如:狀態寄存器)
一個中斷服務子程序中會訪問到的非自動變數(Non-automatic variables)
多線程應用中被幾個任務共享的變數
3)一個參數既可以是const還可以是volatile嗎?解釋為什麼。

可以。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
4)一個指針可以是volatile 嗎?解釋為什麼。
可以。盡管這並不是很常見。一個例子當中斷服務子程序修改一個指向一個buffer的指針時。

下面的函數有什麼錯誤:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
下面是答案:
這段代碼有點變態。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
int square(volatile int *ptr){
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由於*ptr的值可能被意想不到地改變,因此a和b可能是不同的。結果,這段代碼可能並不是你所期望的平方值!正確的代碼如下:
long square(volatile int *ptr){
int a;
a = *ptr;
return a * a;
}

更多linux內核視頻教程文本資料免費獲取後台私信【 內核 】。

3.static const等等的用法,(能說出越多越好)(重點)

² 首先說說const的用法(絕對不能說是常數)

1)在定義的時候必須進行初始化

2)指針可以是const 指針,也可以是指向const對象的指針

3)定義為const的形參,即在函數內部是不能被修改的

4)類的成員函數可以被聲明為正常成員函數,不能修改類的成員變數

5)類的成員函數可以返回的是常對象,即被const聲明的對象

6)類的成員變數是指成員變數不能在聲明時初始化,必須在構造函數的列表裡進行初始化

(註:千萬不要說const是個常數,會被認為是外行人的!!!!哪怕說個只讀也行)

下面的聲明都是什麼意思?
const int a; a是一個正常整型數
int const a; a是一個正常整型數
const int *a; a是一個指向常整型數的指針,整型數是不可修改的,但指針可以
int * const a; a為指向整型數的常指針,指針指向的整型數可以修改,但指針是不可修改的
int const * a const; a是一個指向常整型數的常指針,指針指向的整型數是不可修改的,同時指針也是不可修改的
通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。

Const如何做到只讀?

這些在編譯期間完成,對於內置類型,如int, 編譯器可能使用常數直接替換掉對此變數的引用。而對於結構體不一定。

² 再說說static的用法(三個明顯的作用一定要答出來)

1)在函數體內,一個被聲明為靜態的變數在這一函數被調用過程中維持其值不變。
2)在模塊內(但在函數體外),一個被聲明為靜態的變數可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變數。
3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用

4)類內的static成員變數屬於整個類所擁有,不能在類內進行定義,只能在類的作用域內進行定義

5)類內的static成員函數屬於整個類所擁有,不能包含this指針,只能調用static成員函數

static全局變數與普通的全局變數有什麼區別?static局部變數和普通局部變數有什麼區別?static函數與普通函數有什麼區別?

static全局變數與普通的全局變數有什麼區別:static全局變數只初始化一次,防止在其他文件單元中被引用;
static局部變數和普通局部變數有什麼區別:static局部變數只被初始化一次,下一次依據上一次結果值;
static函數與普通函數有什麼區別:static函數在內存中只有一份,普通函數在每個被調用中維持一份拷貝

4.extern c 作用

告訴編譯器該段代碼以C語言進行編譯。

5.指針和引用的區別

1)引用是直接訪問,指針是間接訪問。

2)引用是變數的別名,本身不單獨分配自己的內存空間,而指針有自己的內存空間

3)引用綁定內存空間(必須賦初值),是一個變數別名不能更改綁定,可以改變對象的值。

總的來說:引用既具有指針的效率,又具有變數使用的方便性和直觀性

6. 關於靜態內存分配和動態內存分配的區別及過程

1) 靜態內存分配是在編譯時完成的,不佔用CPU資源;動態分配內存運行時完成,分配與釋放需要佔用CPU資源;

2)靜態內存分配是在棧上分配的,動態內存是堆上分配的;

3)動態內存分配需要指針或引用數據類型的支持,而靜態內存分配不需要;

4)靜態內存分配是按計劃分配,在編譯前確定內存塊的大小,動態內存分配運行時按需分配。

5)靜態分配內存是把內存的控制權交給了編譯器,動態內存把內存的控制權交給了程序員;

6)靜態分配內存的運行效率要比動態分配內存的效率要高,因為動態內存分配與釋放需要額外的開銷;動態內存管理水平嚴重依賴於程序員的水平,處理不當容易造成內存泄漏。

7. 頭文件中的 ifndef/define/endif 干什麼用

預處理,防止頭文件被重復使用,包括pragma once都是這樣的

8. 宏定義求兩個元素的最小值

#define MIN(A,B) ((A) next;

}

else

{

return NULL;

}

}

Node* pFind = pHead;

while (pCurrent) {

pFind = pFind->next;

pCurrent = pCurrent->next;

}

return pFind;

}

2. 給定一個單向鏈表(長度未知),請遍歷一次就找到中間的指針,假設該鏈表存儲在只讀存儲器,不能被修改

設置兩個指針,一個每次移動兩個位置,一個每次移動一個位置,當第一個指針到達尾節點時,第二個指針就達到了中間節點的位置

處理鏈表問題時,」快行指針「是一種很常見的技巧,快行指針指的是同時用兩個指針來迭代訪問鏈表,只不過其中一個比另一個超前一些。快指針往往先行幾步,或與慢指針相差固定的步數。

node *create() {

node *p1, *p2, *head;

int cycle = 1, x;

head = (node*)malloc(sizeof(node));

p1 = head;

while (cycle)

{

cout > x;

if (x != 0)

{

p2 = (node*)malloc(sizeof(node));

p2->data = x;

p1->next = p2;

p1 = p2;

}

else

{

cycle = 0;

}

}

head = head->next;

p1->next = NULL;

return head;

}

void findmid(node* head) {

node *p1, *p2, *mid;

p1 = head;

p2 = head;

while (p1->next->next != NULL)

{

p1 = p1->next->next;

p2 = p2->next;

mid = p2;

}

}

3. 將一個數組生成二叉排序樹

排序,選數組中間的一個元素作為根節點,左邊的元素構造左子樹,右邊的節點構造有子樹。

4. 查找數組中第k大的數字?

因為快排每次將數組劃分為兩組加一個樞紐元素,每一趟劃分你只需要將k與樞紐元素的下標進行比較,如果比樞紐元素下標大就從右邊的子數組中找,如果比樞紐元素下標小從左邊的子數組中找,如果一樣則就是樞紐元素,找到,如果需要從左邊或者右邊的子數組中再查找的話,只需要遞歸一邊查找即可,無需像快排一樣兩邊都需要遞歸,所以復雜度必然降低。

最差情況如下:假設快排每次都平均劃分,但是都不在樞紐元素上找到第k大第一趟快排沒找到,時間復雜度為O(n),第二趟也沒找到,時間復雜度為O(n/2),第k趟找到,時間復雜度為O(n/2k),所以總的時間復雜度為O(n(1+1/2+....+1/2k))=O(n),明顯比冒泡快,雖然遞歸深度是一樣的,但是每一趟時間復雜度降低。

5. 紅黑樹的定義和解釋?B樹的基本性質?

紅黑樹:

性質1. 節點是紅色或黑色。
性質2. 根節點是黑色。
性質3. 每個葉子結點都帶有兩個空的黑色結點(被稱為黑哨兵),如果一個結點n的只有一個左孩子,那麼n的右孩子是一個黑哨兵;如果結點n只有一個右孩子,那麼n的左孩子是一個黑哨兵。
性質4 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)
性質5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

B樹:

1.所有非葉子結點至多擁有兩個兒子(Left和Right);

2.所有結點存儲一個關鍵字;

3.非葉子結點的左指針指向小於其關鍵字的子樹,右指針指向大於其關鍵字的子樹;

6. 常見的加密演算法?

對稱式加密就是加密和解密使用同一個密鑰。
非對稱式加密就是加密和解密所使用的不是同一個密鑰,通常有兩個密鑰,稱為「公鑰」和「私鑰」,它們兩個必需配對使用。
DES:對稱演算法,數據加密標准,速度較快,適用於加密大量數據的場合;
MD5的典型應用是對一段Message產生fingerprint(指紋),以防止被「篡改」。
RSA是第一個既能用於數據加密也能用於數字簽名的演算法。

7. https?

HTTP下加入SSL層,HTTPS的安全基礎是SSL。

8.有一個IP庫,給你一個IP,如何能夠快速的從中查找到對應的IP段?不用資料庫如何實現?要求省空間
9.簡述一致性hash演算法。

1)首先求memcached伺服器(節點)的哈希值,並將其配置到0 232的圓(continuum)。

2)然後採用同樣的方法求出存儲數據的鍵的哈希值,並映射到相同的圓上。

3)然後從數據映射到的位置開始順時針查找,將數據保存到找到的第一個伺服器上。如果超過232仍然找不到伺服器,就會保存到第一台memcached伺服器上。
11.描述一種hash table的實現方法

1) 除法散列法: p ,令 h(k ) = k mod p ,這里, p 如果選取的是比較大的素數,效果比較好。而且此法非常容易實現,因此是最常用的方法。最直觀的一種,上圖使用的就是這種散列法,公式: index = value % 16,求模數其實是通過一個除法運算得到的。

2) 平方散列法 :求index頻繁的操作,而乘法的運算要比除法來得省時。公式: index = (value * value) >> 28 (右移,除以2^28。記法:左移變大,是乘。右移變小,是除)

3) 數字選擇法:如果關鍵字的位數比較多,超過長整型範圍而無法直接運算,可以選擇其中數字分布比較均勻的若干位,所組成的新的值作為關鍵字或者直接作為函數值。

4) 斐波那契(Fibonacci)散列法:平方散列法的缺點是顯而易見的,通過找到一個理想的乘數index = (value * 2654435769) >> 28

沖突處理:令數組元素個數為 S ,則當 h(k) 已經存儲了元素的時候,依次探查 (h(k)+i) mod S , i=1,2,3…… ,直到找到空的存儲單元為止(或者從頭到尾掃描一圈仍未發現空單元,這就是哈希表已經滿了,發生了錯誤。當然這是可以通過擴大數組范圍避免的)。

12、各類樹結構的實現和應用

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

不選素數的話可能會造成hash出值的范圍和原定義的不一致

14.什麼是平衡二叉樹?

左右子樹都是平衡二叉樹,而且左右子樹的深度差值的約對值不大於1。

15.數組和鏈表的優缺點

數組,在內存上給出了連續的空間。鏈表,內存地址上可以是不連續的,每個鏈表的節點包括原來的內存和下一個節點的信息(單向的一個,雙向鏈表的話,會有兩個)。

數組優於鏈表的:

A. 內存空間佔用的少。

B. 數組內的數據可隨機訪問,但鏈表不具備隨機訪問性。

C. 查找速度快

鏈表優於數組的:

A. 插入與刪除的操作方便。

B. 內存地址的利用率方面鏈表好。

C. 方便內存地址擴展。

17.最小堆插入,刪除編程實現

18. 4G的long型整數中找到一個最大的,如何做?

每次從磁碟上盡量多讀一些數到內存區,然後處理完之後再讀入一批。減少IO次數,自然能夠提高效率。分批讀入選取最大數,再對緩存的最大數進行快排。

19. 有千萬個string在內存怎麼高速查找,插入和刪除?

對千萬個string做hash,可以實現高速查找,找到了,插入和刪除就很方便了。關鍵是如何做hash,對string做hash,要減少碰撞頻率。

在內存中維護一個大小為10000的最小堆,每次從文件讀一個數,與最小堆的堆頂元素比較,若比堆頂元素大,則替換掉堆頂元素,然後調整堆。最後剩下的堆內元素即為最大的1萬個數,演算法復雜度為O(NlogN)

(1)全局洗牌法

a)首先生成一個數組,大小為54,初始化為1~54

b)按照索引1到54,逐步對每一張索引牌進行洗牌,首先生成一個余數 value = rand %54,那麼我們的索引牌就和這個余數牌進行交換處理

c)等多索引到54結束後,一副牌就洗好了

(2)局部洗牌法:索引牌從1開始,到54結束。這一次索引牌只和剩下還沒有洗的牌進行交換, value = index + rand() %(54 - index)

演算法復雜度是O(n)

22.請分別用遞歸和非遞歸方法,先序遍歷二叉樹

24.其他各種排序方法

25.哈希表沖突解決方法?

常見的hash演算法如下:

解決沖突的方法:

也叫散列法,主要思想是當出現沖突的時候,以關鍵字的結果值作為key值輸入,再進行處理,依次直到沖突解決

線性地址再散列法

當沖突發生時,找到一個空的單元或者全表

二次探測再散列

沖突發生時,在表的左右兩側做跳躍式的探測

偽隨機探測再散列

同時構造不同的哈希函數

將同樣的哈希地址構造成一個同義詞的鏈表

建立一個基本表和溢出區,凡是和基本元素發生沖突都填入溢出區

六、系統架構

1.設計一個服務,提供遞增的SessionID服務,要求保證服務的高可靠性,有哪些方案?集中式/非集中式/分布式

2.多台伺服器要執行計劃任務,但只有拿到鎖的任務才能執行,有一個中心伺服器來負責分配鎖,但要保證服務的高可靠性。

3.如何有效的判斷伺服器是否存活?伺服器是否踢出集群的決策如何產生?

4.兩個伺服器如何在同一時刻獲取同一數據的時候保證只有一個伺服器能訪問到數據?

可以採用隊列進行處理,寫一個隊列介面保證同一時間只有一個進程能夠訪問到數據,或者對於存取資料庫的來說,資料庫也是可以加鎖處理的

5. 編寫高效伺服器程序,需要考慮的因素

性能對伺服器程序來說是至關重要的了,畢竟每個客戶都期望自己的請求能夠快速的得到響應並處理。那麼影響伺服器性能的首要因素應該是:

(1)系統的硬體資源,比如說CPU個數,速度,內存大小等。不過由於硬體技術的飛速發展,現代伺服器都不缺乏硬體資源。因此,需要考慮的主要問題是如何從「軟環境」來提升伺服器的性能。

伺服器的」軟環境「

(2)一方面是指系統的軟體資源,比如操作系統允許用戶打開的最大文件描述符數量

(3)另一方面指的就是伺服器程序本身,即如何從編程的角度來確保伺服器的性能。

主要就要考慮大量並發的處理這涉及到使用進程池或線程池實現高效的並發模式(半同步/半非同步和領導者/追隨者模式),以及高效的邏輯處理方式--有限狀態機內存的規劃使用比如使用內存池,以空間換時間,被事先創建好,避免動態分配,減少了伺服器對內核的訪問頻率,數據的復制,伺服器程序還應該避免不必要的數據復制,尤其是當數據復制發生在用戶空間和內核空間之間時。如果內核可以直接處理從socket或者文件讀入的數據,則應用程序就沒必要將這些數據從內核緩沖區拷貝到應用程序緩沖區中。這里所謂的「直接處理」,是指應用程序不關心這些數據的具體內容是什麼,不需要對它們作任何分析。比如說ftp伺服器,當客戶請求一個文件時,伺服器只需要檢測目標文件是否存在,以及是否有許可權讀取就可以了,不需要知道這個文件的具體內容,這樣的話ftp伺服器就不需要把目標文件讀入應用程序緩沖區然後調用send函數來發送,而是直接使用「零拷貝」函數sendfile直接將其發送給客戶端。另外,用戶代碼空間的數據賦值也應該盡可能的避免復制。當兩個工作進程之間需要傳遞大量的數據時,我們就應該考慮使用共享內存來在他們直接直接共享這些數據,而不是使用管道或者消息隊列來傳遞。上下文切換和鎖:並發程序必須考慮上下文的切換問題,即進程切換或線程切換所導致的系統開銷。即時I/O密集型伺服器也不應該使用過多的工作線程(或工作進程),否則進程間切換將佔用大量的CPU時間,伺服器真正處理業務邏輯的CPU時間比重就下降了。因此為每個客戶連接都創建一個工作線程是不可取的。應該使用某種高效的並發模式。(半同步半非同步或者說領導者追隨者模式)另一個問題就是共享資源的加鎖保護。鎖通常被認為是導致伺服器效率低下的一個因素,因為由他引入的代碼不僅不處理業務邏輯,而且需要訪問內核資源,因此如果伺服器有更好的解決方案,應該盡量避免使用鎖。或者說伺服器一定非要使用鎖的話,盡量使用細粒度的鎖,比如讀寫鎖,當工作線程都只讀一塊內存區域時,讀寫鎖不會增加系統開銷,而只有當需要寫時才真正需要鎖住這塊內存區域。對於高峰和低峰的伸縮處理,適度的緩存。

6. QQ飛車新用戶注冊時,如何判斷新注冊名字是否已存在?(數量級:幾億)

可以試下先將用戶名通過編碼方式轉換,如轉換64位整型。然後設置N個區間,每個區間為2^64/N的大小。對於新的用戶名,先通過2分尋找該用戶名屬於哪個區間,然後在在這個區間,做一個hash。對於不同的時間復雜度和內存要求可以設置不同N的大小~

加一些基礎的技術面試之外的職業素養的面試問題

1.你在工作中犯了個錯誤,有同事打你小報告,你如何處理?

a.同事之間應該培養和形成良好的同事關系,就是要互相支持而不是互相拆台,互相學習,互相幫助,共同進步。

b.如果小報告里邊的事情都是事實也就是說確實是本人做的不好不對的方面,那麼自己應該有則改之,提高自己。如果小報告里邊的事

情全部不是事實,就是說確實誣陷,那麼應該首先堅持日久見人心的態度,持之以恆的把本職工作做好,然後在必要的時候通過適當的

方式和領導溝通,相信領導會知道的。

2.你和同事合作完成一個任務,結果任務錯過了截止日期,你如何處理?

3.職業規劃?

4.離職原因?

5. 項目中遇到的難題,你是如何解決的?

A.時間 b要求 c.方法

❷ linux內核同步問題

Linux內核設計與實現 十、內核同步方法

手把手教Linux驅動5-自旋鎖、信號量、互斥體概述

== 基礎概念: ==

並發 :多個執行單元同時進行或多個執行單元微觀串列執行,宏觀並行執行

競態 :並發的執行單元對共享資源(硬體資源和軟體上的全局變數)的訪問而導致的竟態狀態。

臨界資源 :多個進程訪問的資源

臨界區 :多個進程訪問的代碼段

== 並發場合: ==

1、單CPU之間進程間的並發 :時間片輪轉,調度進程。 A進程訪問列印機,時間片用完,OS調度B進程訪問列印機。

2、單cpu上進程和中斷之間並發 :CPU必須停止當前進程的執行中斷;

3、多cpu之間

4、單CPU上中斷之間的並發

== 使用偏向: ==

==信號量用於進程之間的同步,進程在信號量保護的臨界區代碼裡面是可以睡眠的(需要進行進程調度),這是與自旋鎖最大的區別。==

信號量又稱為信號燈,它是用來協調不同進程間的數據對象的,而最主要的應用是共享內存方式的進程間通信。本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取狀況。它負責協調各個進程,以保證他們能夠正確、合理的使用公共資源。它和spin lock最大的不同之處就是:無法獲取信號量的進程可以睡眠,因此會導致系統調度。

1、==用於進程與進程之間的同步==

2、==允許多個進程進入臨界區代碼執行,臨界區代碼允許睡眠;==

3、信號量本質是==基於調度器的==,在UP和SMP下沒有區別;進程獲取不到信號量將陷入休眠,並讓出CPU;

4、不支持進程和中斷之間的同步

5、==進程調度也是會消耗系統資源的,如果一個int型共享變數就需要使用信號量,將極大的浪費系統資源==

6、信號量可以用於多個線程,用於資源的計數(有多種狀態)

==信號量加鎖以及解鎖過程:==

sema_init(&sp->dead_sem, 0); / 初始化 /

down(&sema);

臨界區代碼

up(&sema);

==信號量定義:==

==信號量初始化:==

==dowm函數實現:==

==up函數實現:==

信號量一般可以用來標記可用資源的個數。

舉2個生活中的例子:

==dowm函數實現原理解析:==

(1)down

判斷sem->count是否 > 0,大於0則說明系統資源夠用,分配一個給該進程,否則進入__down(sem);

(2)__down

調用__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);其中TASK_UNINTERRUPTIBLE=2代表進入睡眠,且不可以打斷;MAX_SCHEDULE_TIMEOUT休眠最長LONG_MAX時間;

(3)list_add_tail(&waiter.list, &sem->wait_list);

把當前進程加入到sem->wait_list中;

(3)先解鎖後加鎖;

進入__down_common前已經加鎖了,先把解鎖,調用schele_timeout(timeout),當waiter.up=1後跳出for循環;退出函數之前再加鎖;

Linux內核ARM構架中原子變數的底層實現研究

rk3288 原子操作和原子位操作

原子變數適用於只共享一個int型變數;

1、原子操作是指不被打斷的操作,即它是最小的執行單位。

2、最簡單的原子操作就是一條條的匯編指令(不包括一些偽指令,偽指令會被匯編器解釋成多條匯編指令)

==常見函數:==

==以atomic_inc為例介紹實現過程==

在Linux內核文件archarmincludeasmatomic.h中。 執行atomic_read、atomic_set這些操作都只需要一條匯編指令,所以它們本身就是不可打斷的。 需要特別研究的是atomic_inc、atomic_dec這類讀出、修改、寫回的函數。

所以atomic_add的原型是下面這個宏:

atomic_add等效於:

result(%0) tmp(%1) (v->counter)(%2) (&v->counter)(%3) i(%4)

注意:根據內聯匯編的語法,result、tmp、&v->counter對應的數據都放在了寄存器中操作。如果出現上下文切換,切換機制會做寄存器上下文保護。

(1)ldrex %0, [%3]

意思是將&v->counter指向的數據放入result中,並且(分別在Local monitor和Global monitor中)設置獨占標志。

(2)add %0, %0, %4

result = result + i

(3)strex %1, %0, [%3]

意思是將result保存到&v->counter指向的內存中, 此時 Exclusive monitors會發揮作用,將保存是否成功的標志放入tmp中。

(4) teq %1, #0

測試strex是否成功(tmp == 0 ??)

(5)bne 1b

如果發現strex失敗,從(1)再次執行。

Spinlock 是內核中提供的一種比較常見的鎖機制,==自旋鎖是「原地等待」的方式解決資源沖突的==,即,一個線程獲取了一個自旋鎖後,另外一個線程期望獲取該自旋鎖,獲取不到,只能夠原地「打轉」(忙等待)。由於自旋鎖的這個忙等待的特性,註定了它使用場景上的限制 —— 自旋鎖不應該被長時間的持有(消耗 CPU 資源),一般應用在==中斷上下文==。

1、spinlock是一種死等機制

2、信號量可以允許多個執行單元進入,spinlock不行,一次只能允許一個執行單元獲取鎖,並且進入臨界區,其他執行單元都是在門口不斷的死等

3、由於不休眠,因此spinlock可以應用在中斷上下文中;

4、由於spinlock死等的特性,因此臨界區執行代碼盡可能的短;

==spinlock加鎖以及解鎖過程:==

spin_lock(&devices_lock);

臨界區代碼

spin_unlock(&devices_lock);

==spinlock初始化==

==進程和進程之間同步==

==本地軟中斷之間同步==

==本地硬中斷之間同步==

==本地硬中斷之間同步並且保存本地中斷狀態==

==嘗試獲取鎖==

== arch_spinlock_t結構體定義如下: ==

== arch_spin_lock的實現如下: ==

lockval(%0) newval(%1) tmp(%2) &lock->slock(%3) 1 << TICKET_SHIFT(%4)

(1)ldrex %0, [%3]

把lock->slock的值賦值給lockval;並且(分別在Local monitor和Global monitor中)設置獨占標志。

(2)add %1, %0, %4

newval =lockval +(1<<16); 相當於next+1;

(3)strex %2, %1, [%3]

newval =lockval +(1<<16); 相當於next+1;

意思是將newval保存到 &lock->slock指向的內存中, 此時 Exclusive monitors會發揮作用,將保存是否成功的標志放入tmp中。

(4) teq %2, #0

測試strex是否成功

(5)bne 1b

如果發現strex失敗,從(1)再次執行。

通過上面的分析,可知關鍵在於strex的操作是否成功的判斷上。而這個就歸功於ARM的Exclusive monitors和ldrex/strex指令的機制。

(6)while (lockval.tickets.next != lockval.tickets.owner)

如何lockval.tickets的next和owner是否相等。相同則跳出while循環,否則在循環內等待判斷;

* (7)wfe()和smp_mb() 最終調用#define barrier() asm volatile ("": : :"memory") *

阻止編譯器重排,保證編譯程序時在優化屏障之前的指令不會在優化屏障之後執行。

== arch_spin_unlock的實現如下: ==

退出鎖時:tickets.owner++

== 出現死鎖的情況: ==

1、擁有自旋鎖的進程A在內核態阻塞了,內核調度B進程,碰巧B進程也要獲得自旋鎖,此時B只能自旋轉。 而此時搶占已經關閉,(單核)不會調度A進程了,B永遠自旋,產生死鎖。

2、進程A擁有自旋鎖,中斷到來,CPU執行中斷函數,中斷處理函數,中斷處理函數需要獲得自旋鎖,訪問共享資源,此時無法獲得鎖,只能自旋,產生死鎖。

== 如何避免死鎖: ==

1、如果中斷處理函數中也要獲得自旋鎖,那麼驅動程序需要在擁有自旋鎖時禁止中斷;

2、自旋鎖必須在可能的最短時間內擁有

3、避免某個獲得鎖的函數調用其他同樣試圖獲取這個鎖的函數,否則代碼就會死鎖;不論是信號量還是自旋鎖,都不允許鎖擁有者第二次獲得這個鎖,如果試圖這么做,系統將掛起;

4、鎖的順序規則(a) 按同樣的順序獲得鎖;b) 如果必須獲得一個局部鎖和一個屬於內核更中心位置的鎖,則應該首先獲取自己的局部鎖 ;c) 如果我們擁有信號量和自旋鎖的組合,則必須首先獲得信號量;在擁有自旋鎖時調用down(可導致休眠)是個嚴重的錯誤的;)

== rw(read/write)spinlock: ==

加鎖邏輯:

1、假設臨界區內沒有任何的thread,這個時候任何的讀線程和寫線程都可以鍵入

2、假設臨界區內有一個讀線程,這時候信賴的read線程可以任意進入,但是寫線程不能進入;

3、假設臨界區有一個寫線程,這時候任何的讀、寫線程都不可以進入;

4、假設臨界區內有一個或者多個讀線程,寫線程不可以進入臨界區,但是寫線程也無法阻止後續的讀線程繼續進去,要等到臨界區所有的讀線程都結束了,才可以進入,可見:==rw(read/write)spinlock更加有利於讀線程;==

== seqlock(順序鎖): ==

加鎖邏輯:

1、假設臨界區內沒有任何的thread,這個時候任何的讀線程和寫線程都可以鍵入

2、假設臨界區內沒有寫線程的情況下,read線程可以任意進入;

3、假設臨界區有一個寫線程,這時候任何的讀、寫線程都不可以進入;

4、假設臨界區內只有read線程的情況下,寫線程可以理解執行,不會等待,可見:==seqlock(順序鎖)更加有利於寫線程;==

讀寫速度 CPU > 一級緩存 > 二級緩存 > 內存 ,因此某一個CPU0的lock修改了,其他的CPU的lock就會失效;那麼其他CPU就會依次去L1 L2和主存中讀取lock值,一旦其他CPU去讀取了主存,就存在系統性能降低的風險;

mutex用於互斥操作。

互斥體只能用於一個線程,資源只有兩種狀態(佔用或者空閑)

1、mutex的語義相對於信號量要簡單輕便一些,在鎖爭用激烈的測試場景下,mutex比信號量執行速度更快,可擴展

性更好,

2、另外mutex數據結構的定義比信號量小;、

3、同一時刻只有一個線程可以持有mutex

4、不允許遞歸地加鎖和解鎖

5、當進程持有mutex時,進程不可以退出。

• mutex必須使用官方API來初始化。

• mutex可以睡眠,所以不允許在中斷處理程序或者中斷下半部中使用,例如tasklet、定時器等

==常見操作:==

struct mutex mutex_1;

mutex_init(&mutex_1);

mutex_lock(&mutex_1)

臨界區代碼;

mutex_unlock(&mutex_1)

==常見函數:==

=

閱讀全文

與編程中上下文切換是什麼意思相關的資料

熱點內容
香港中文字幕電影 瀏覽:495
美國光頭男優 瀏覽:404
受保護的word文檔如何編輯 瀏覽:406
神馬影院4k4k 瀏覽:497
法國電影流浪愛侶在線觀看 瀏覽:958
看美劇英劇去哪個app 瀏覽:428
win10如何將兩個分區合並 瀏覽:661
excel宏導出成文件 瀏覽:550
求個干凈的電影網 瀏覽:722
銀盛app為什麼說我賬戶凍結了 瀏覽:624
潤心音樂,電影 瀏覽:104
sp誡訓父子 瀏覽:57
現在電影院用的多少幀率 瀏覽:107
免費網站不收費片 瀏覽:765
java證書解析 瀏覽:242
大數據檢驗檢測 瀏覽:808
測名網站哪個比較好 瀏覽:912
手機克隆後的數據存在哪裡 瀏覽:201
linux下lib文件使用 瀏覽:578
有希望的男人女主是誰 瀏覽:956

友情鏈接