天天看點

《linux多線程服務端程式設計》---- C++基礎前奏1 mutable2 C++二階構造3 野指針和空懸指針4 observer模式5 值語義6 spinlock自旋鎖7 寫時複制(COW)8 Explicit關鍵字9 讀寫鎖10 Read-Copy-Update(RCU)11 POD資料

1 mutable

在C++中,mutable也是為了突破const的限制而設定的。被mutable修飾的變量,将永遠處于可變的狀态,即使在一個const函數中。

該關鍵字修飾類中資料成員時,會釋放掉non-static成員變量的bitwise constnes限制,即使在const成員函數依然可以修改該資料成員變量。

Immutable object (不可變對象) :當對象被建立後,你不能修改對象的狀态以及字段。

2 C++二階構造

【C++深度剖析教程4】C++的二階構造模式_厚積薄發-CSDN部落格

3 野指針和空懸指針

野指針:

野指針就是指針指向的位置是不可知的(随機的、不正确的、沒有明确限制的)指針變量在定義時如果未初始化,其值是随機的,指針變量的值是别的變量的位址,意味着指針指向了一個位址是不确定的變量,此時去解引用就是去通路了一個不确定的位址,是以結果是不可知的。

成因:

(1)指針變量未初始化

任何指針變量剛被建立時不會自動成為NULL指針,它的預設值是随機的,它會亂指一氣。是以,指針變量在建立的同時應當被初始化,要麼将指針設定為NULL,要麼讓它指向合法的記憶體。

(2)指針釋放後之後未置空

有時指針在free或delete後未指派 NULL,便會使人以為是合法的。别看free和delete的名字(尤其是delete),它們隻是把指針所指的記憶體給釋放掉,但并沒有把指針本身幹掉。此時指針指向的就是“垃圾”記憶體。釋放後的指針應立即将指針置為NULL,防止産生“野指針”。

(3)指針操作超越變量作用域

不要傳回指向棧記憶體的指針或引用,因為棧記憶體在函數結束時會被釋放。

空指針:

 #define NULL    ((void *)0) 

在記憶體配置設定方面,較小的位址是不用來存放資料的,也不允許程式通路的。是以,指針指向了它,就是這個指針不能操作它指向的這塊較小的位址。

簡單來說,空指針有指向,但是它指向的位址是特殊的,該位址不允許存放資料和不允許程式通路,是以空指針不能操作該位址裡的東西,我們就了解為“指針指向了空,無法操作了”。

void * 類型指針,

這個類型指針指向了實實在在的存放資料的位址,但是該位址存放的資料的資料類型我們暫時不知道。

空懸指針

指向已經銷毀的對象或已經回收的位址。

4 observer模式

C++ 觀察者模式_上善若水-CSDN部落格_cpp 觀察者模式

5 值語義

所謂值語義是一個對象被系統标準的複制方式複制後,與被複制的對象之間毫無關系,可以彼此獨立改變互不影響。在C++中使用拷貝構造和指派。

與值語義對應的是“對象語義/object sematics”,或者叫做引用語義(reference sematics),由于“引用”一詞在 C++ 裡有特殊含義,是以我在本文中使用“對象語義”這個術語。對象語義指的是面向對象意義下的對象,對象拷貝是禁止的。例如 muduo 裡的 Thread 是對象語義,拷貝 Thread 是無意義的,也是被禁止的:因為 Thread 代表線程,拷貝一個 Thread 對象并不能讓系統增加一個一模一樣的線程。

值語義的對象要麼是 stack object,或者直接作為其他 object 的成員,是以我們不用擔心它的生命期(一個函數使用自己stack上的對象,一個成員函數使用自己的資料成員對象)。相反,對象語義的 object 由于不能拷貝,我們隻能通過指針或引用來使用它。

6 spinlock自旋鎖

自旋鎖是專為防止多處理器并發而引入的一種鎖,它在核心中大量應用于中斷處理等部分

何謂自旋鎖?它是為實作保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多隻能有一個保持者,也就說,在任何時刻最多隻能有一個執行單元獲得鎖。但是兩者在排程機制上略有不同。對于互斥鎖,如果資源已經被占用,資源申請者隻能進入睡眠狀态。但是自旋鎖不會引起調用者睡眠,如果自旋鎖已經被别的執行單元保持,調用者就一直循環在那裡看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是是以而得名。

自旋鎖是一種比較低級的保護資料結構或代碼片段的原始方式,這種鎖可能存在兩個問題:

(1)死鎖

試圖遞歸地獲得自旋鎖必然會引起死鎖:遞歸程式的持有執行個體在第二個執行個體循環,以試圖獲得相同自旋鎖時,不會釋放此自旋鎖。在遞歸程式中使用自旋鎖應遵守下列政策:遞歸程式決不能在持有自旋鎖時調用它自己,也決不能在遞歸調用時試圖獲得相同的自旋鎖。此外如果一個程序已經将資源鎖定,那麼,即使其它申請這個資源的程序不停地瘋狂“自旋”,也無法獲得資源,進而進入死循環。

(2) 占用過多CPU資源

過多占用cpu資源。如果不加限制,由于申請者一直在循環等待,是以自旋鎖在鎖定的時候,如果不成功,不會睡眠,會持續的嘗試,單cpu的時候自旋鎖會讓其它process動不了. 是以,一般自旋鎖實作會有一個參數限定最多持續嘗試次數. 超出後, 自旋鎖放棄目前time slice. 等下一次機會。

自旋鎖比較适用于鎖使用者保持鎖時間比較短的情況。正是由于自旋鎖使用者一般保持鎖時間非常短,是以選擇自旋而不是睡眠是非常必要的,自旋鎖的效率遠高于互斥鎖。

信号量和讀寫信号量适合于保持時間較長的情況,它們會導緻調用者睡眠,是以隻能在程序上下文使用,而自旋鎖适合于保持時間非常短的情況,它可以在任何上下文使用。如果被保護的共享資源隻在程序上下文通路,使用信号量保護該共享資源非常合适,如果對共享資源的通路時間非常短,自旋鎖也可以。但是如果被保護的共享資源需要在中斷上下文通路(包括底半部即中斷處理句柄和頂半部即軟中斷),就必須使用自旋鎖。

7 寫時複制(COW)

Copy On Write機制了解一下_u012501054的部落格-CSDN部落格_copy on write

8 Explicit關鍵字

C++中的explicit關鍵字隻能用于修飾隻有一個參數的類構造函數, 它的作用是表明該構造函數是顯示的, 而非隐式的, 跟它相對應的另一個關鍵字是implicit, 意思是隐藏的,類構造函數預設情況下即聲明為implicit(隐式).

C++ explicit關鍵字詳解 - 網名還沒想好 - 部落格園 (cnblogs.com)

9 讀寫鎖

《linux多線程服務端程式設計》---- C++基礎前奏1 mutable2 C++二階構造3 野指針和空懸指針4 observer模式5 值語義6 spinlock自旋鎖7 寫時複制(COW)8 Explicit關鍵字9 讀寫鎖10 Read-Copy-Update(RCU)11 POD資料

10 Read-Copy-Update(RCU)

RCU就是指讀-拷貝修改,它是基于其原理命名的。對于被RCU保護的共享資料結構,讀操作不需要獲得任何鎖就可以通路,但寫操作在通路它時首先拷貝一個副本,然後對副本進行修改,最後在适當的時機把指向原來資料的指針重新指向新的被修改的資料。這個時機就是所有引用該資料的CPU都退出對共享資料的操作。

Linux核心中記憶體管理大量的運用到了RCU機制。為每個記憶體對象增加了一個原子計數器用來繼續該對象目前通路數。當沒有其他程序在通路該對象時(計數器為0),才允許回收該記憶體。

從這個流程可以看出,RCU類似于一種讀寫鎖的優化,用于解決讀和寫之間的同步問題。比較适合讀多,寫少的情況,當寫操作過多的時候,這裡的拷貝和修改的成本同樣也很大。(寫操作和寫操作之間的同步還需要其它機制來保證)。

11 POD資料

POD 是 Plain Old Data 的縮寫,是 C++ 定義的一類資料結構概念,比如 int、float 等都是 POD 類型的。Plain 代表它是一個普通類型,Old 代表它是舊的,與幾十年前的 C 語言相容,那麼就意味着可以使用 memcpy() 這種最原始的函數進行操作。兩個系統進行交換資料,如果沒有辦法對資料進行語義檢查和解釋,那就隻能以非常底層的資料形式進行互動,而擁有 POD 特征的類或者結構體通過二進制拷貝後依然能保持資料結構不變。也就是說,能用 C 的 memcpy() 等函數進行操作的類、結構體就是 POD 類型的資料。

基本上談到這個概念,一般都是說某某 class、struct、union 是不是 POD 類型的。

是不是 POD 類型的,可以用 is_pod<T>::value 來判斷。那什麼樣的類、結構體是擁有 POD 特性的呢?要求有兩個:一個是它必須很平凡、很普通;另一個是布局有序。

什麼是 POD 資料類型? - 知乎 (zhihu.com)

繼續閱讀