C++面經(jīng)(基礎(chǔ)知識點(diǎn))

C++語言的八股文

C++面向?qū)ο蟮奶匦?/h2>
  • 封裝——隱藏對象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對外公開接口和對象進(jìn)行交互转质,將數(shù)據(jù)和操作數(shù)據(jù)的方法進(jìn)行有機(jī)結(jié)合。
  • 繼承——允許程序員在保持父類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能建丧,這樣產(chǎn)生的新類腿堤,稱為子類阀坏;父類和子類存在父子關(guān)系,即:
    • 子類擁有父類的所有屬性和行為
    • 子類對象可以作為父類對象使用
    • 子類中可以添加父類沒有的方法和屬性
  • 多態(tài)——為不同數(shù)據(jù)類型的實(shí)體提供統(tǒng)一的接口笆檀。
    • 動態(tài)多態(tài)(dynamic polymorphism):通過類繼承機(jī)制和虛函數(shù)機(jī)制生效于運(yùn)行期忌堂。可以優(yōu)雅地處理異質(zhì)對象集合酗洒,只要其共同的基類定義了虛函數(shù)的接口士修。也被稱為子類型多態(tài)(Subtype polymorphism)或包含多態(tài)(inclusion polymorphism)。在面向?qū)ο蟪绦蛟O(shè)計(jì)中樱衷,這被直接稱為多態(tài)棋嘲。
    • 靜態(tài)多態(tài)(static polymorphism):模板也允許將不同的特殊行為和單個泛化記號相關(guān)聯(lián),由于這種關(guān)聯(lián)處理于編譯期而非運(yùn)行期矩桂,因此被稱為“靜態(tài)”沸移。可以用來實(shí)現(xiàn)類型安全、運(yùn)行高效的同質(zhì)對象集合操作雹锣。(通過函數(shù)重載和模板來實(shí)現(xiàn))

虛函數(shù)

  • 指被virtual關(guān)鍵字修飾的成員函數(shù)网沾。實(shí)現(xiàn)多態(tài)性,通過指向派生類的基類指針或引用蕊爵,訪問派生類中同名覆蓋成員函數(shù)辉哥。
  • 在類對象的頭4個字節(jié)中,有一個指向這個虛函數(shù)表的指針在辆,稱為Vptr证薇;(一個類的多個實(shí)例共享同一個虛函數(shù)表)
  • 構(gòu)造函數(shù)不可以有虛函數(shù)虹统,析構(gòu)函數(shù)可以有虛函數(shù)吝岭。(析構(gòu)函數(shù)常常被聲明為virtual眶拉,這是因?yàn)楫?dāng)父類的析構(gòu)函數(shù)未聲明為virtual時建钥,如果父類指針指向一個子類的對象碱呼,那么當(dāng)delete該指針時梨撞,子類的析構(gòu)函數(shù)不會被調(diào)用堕伪,從而造成內(nèi)存泄漏)

虛繼承和虛基類

  • 為了解決多繼承時的命名沖突和冗余數(shù)據(jù)問題挤渔,C++ 提出了虛繼承窗市,使得在派生類中只保留一份間接基類的成員先慷。
  • 虛繼承的目的是讓某個類做出聲明,承諾愿意共享它的基類咨察。其中论熙,這個被共享的基類就稱為虛基類(Virtual Base Class)。在這種機(jī)制下摄狱,不論虛基類在繼承體系中出現(xiàn)了多少次脓诡,在派生類中都只包含一份虛基類的成員。

指針和引用

  • 引用:引用可以看作是一個指針常量來實(shí)現(xiàn)的媒役,引用是一個內(nèi)存對象的別名祝谚。
  • 指針:指針指向一個內(nèi)存對象,保存了這個對象的內(nèi)存地址酣衷。
指針和引用的不同點(diǎn) 指針 引用
是否可以為空
是否必須初始化
初始化后是否可以改變
是否有const
是否需要分配內(nèi)存空間
訪問對象的方式 間接訪問 直接訪問
大小 指針本身的大小交惯,32位系統(tǒng)為4字節(jié),64位系統(tǒng)為8字節(jié) 引用對象的大小
++自增運(yùn)算符 指向下一個地址 所引用的對象執(zhí)行自增操作

內(nèi)置數(shù)組和指針

  • 內(nèi)置數(shù)組:內(nèi)置數(shù)組是用于儲存多個相同類型數(shù)據(jù)的集合穿仪。
  • 指針:指針指向一個內(nèi)存對象席爽,保存了這個對象的內(nèi)存地址。
不同點(diǎn) 內(nèi)置數(shù)組 指針
賦值 一個個元素賦值或拷貝 同一類型的指針可以相互賦值
存儲方式 連續(xù)存放于靜態(tài)區(qū)或棧上啊片。 很靈活只锻,可以指向任意類型的數(shù)據(jù)。指針的類型說明了它所指向地址空間的內(nèi)存钠龙。
sizeof大小 數(shù)組元素個數(shù) ? 單個元素所占大小 根據(jù)操作系統(tǒng)的位數(shù)來確定炬藤,32位大小為4御铃,64位大小為8
傳參 傳遞指向該數(shù)組的指針 傳遞本身
  • 易混淆點(diǎn):
    • 指針數(shù)組:一個元素對象為指針的數(shù)組。
    • 數(shù)組指針:指向數(shù)組的指針沈矿。

static關(guān)鍵字

  • 控制可見范圍上真,不用擔(dān)心重名問題。
  • 保持變量內(nèi)容的持久羹膳。
  • 默認(rèn)初始化為0睡互。
  • 類成員聲明static,static成員為類所擁有陵像,而非實(shí)例所擁有就珠。

全局靜態(tài)變量和局部靜態(tài)變量的異同

  • 不同點(diǎn):作用域范圍不同,全局靜態(tài)變量具有文件作用域醒颖,局部靜態(tài)變量具有塊作用域妻怎。
  • 相同點(diǎn):生命周期都是所屬模塊裝載到所屬模塊卸載。

C++11新特性

  • nullptr

  • 類型推導(dǎo)(auto和decltype)泞歉,

    • auto是讓編譯器通過初始值來推算變量的類型(用來縮寫類型和簡化聲明)逼侦;(auto不能傳遞const特性
    • decltype在C++中,作為操作符腰耙,用于查詢表達(dá)式的數(shù)據(jù)類型;主要是為泛型編程而設(shè)計(jì)榛丢,以解決泛型編程中,由于有些類型由模板參數(shù)決定挺庞,而難以(甚至不可能)表示之的問題晰赞。
  • 區(qū)間迭代

for(auto ch : s){
}
  • 構(gòu)造函數(shù)(委托構(gòu)造,繼承構(gòu)造)
  • Lambda表達(dá)式
  • 新增容器(std::array选侨,std::forward_list掖鱼,無序容器,std::tuple)侵俗,
  • 服務(wù)于string的正則表達(dá)式(std::regex锨用,std::regex_match->std::match_results)

 if (std::regex_match ("subject", std::regex("(sub)(.*)") ))
    std::cout << "匹配成功\n";
  • 語言級線程支持(std::thread丰刊,std::mutex/std::unique_lock隘谣,std::condition_variable,std::future/std::packaged_task)

  • 右值引用和move語義

  • 智能指針(unique_ptr啄巧、shared_ptr寻歧、weak_ptr)

  • std::move和std::forward

    • std::move(t)用來表示對象t可以被移動,即允許t所占有的資源轉(zhuǎn)移到另一對象上秩仆。比較特別使用方式是:用std::move生成一個xvalue(xvalue是定義的右值码泛,有實(shí)體,可以被移動澄耍。)*表達(dá)式來標(biāo)識它的參數(shù)t噪珊,等價于通過static_cast轉(zhuǎn)換為右值引用類型(static_cast<typename std::remove_reference<T>::type&&>(t)晌缘。
    • std::forward<T>,將左值轉(zhuǎn)換為左值還是右值取決于T的類型痢站;只能將右值轉(zhuǎn)換為右值磷箕,不允許右值轉(zhuǎn)換為左值。
  • std::bind

    • 函數(shù)模板bind為f生成一個轉(zhuǎn)發(fā)調(diào)用包裝器阵难。調(diào)用這個包裝器相當(dāng)于調(diào)用f岳枷,并將其一些參數(shù)綁定到args上。
#include <iostream>
#include <functional>

void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout<< n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}


int main(){
   using namespace std::placeholders;
    std::cout << "1) argument reordering and pass-by-reference: ";
    int n = 7;
    // (_1 and _2 are from std::placeholders, and represent future
    // arguments that will be passed to f1)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
                    // makes a call to f(2, 42, 1, n, 7)

  return 0;
}
//輸出為:argument reordering and pass-by-reference: 2 42 1 10 7

為什么使用C++11呜叫?

  • 更友好的語法規(guī)則空繁。(auto、lambda)
  • 更強(qiáng)大的容器庫朱庆。(無序容器)
  • 更強(qiáng)大的性能優(yōu)勢盛泡。(右值引用,定制模板)
  • 內(nèi)存泄漏娱颊。(智能指針)
  • 更清晰的代碼意圖饭于。(override、final和nullptr)
  • 編譯期錯誤檢查维蒙。(static_assert)

智能指針

  • 智能指針主要用于管理在堆上分配的內(nèi)存掰吕,它將普通的指針封裝為一個棧對象。
  • 當(dāng)棧對象的生存周期結(jié)束后颅痊,會在析構(gòu)函數(shù)中釋放掉申請的內(nèi)存殖熟,從而防止內(nèi)存泄漏。
名稱 描述
auto_ptr 這個類模板因存在潛在的內(nèi)存崩潰問題在c++ 11中已棄用斑响。取代它的是unique_ptr菱属。
unique_ptr 實(shí)現(xiàn)獨(dú)占式擁有或嚴(yán)格擁有概念,保證同一時間內(nèi)只有一個智能指針可以指向該對象舰罚。
shared_ptr 實(shí)現(xiàn)共享式擁有概念纽门。多個智能指針可以指向相同對象,該對象和其相關(guān)資源會在“最后一個引用被銷毀”時候釋放营罢。
weak_ptr 一種不控制對象生命周期的智能指針, 它指向一個shared_ptr管理的對象赏陵,主要用作解決當(dāng)兩個對象互相使用一個shared_ptr成員變量指向?qū)Ψ剑瑫斐裳h(huán)引用饲漾,使引用計(jì)數(shù)失效蝙搔,從而導(dǎo)致內(nèi)存泄漏的問題。

shared_ptr如何實(shí)現(xiàn)考传?

  • T類型為任意類型
  • 需要實(shí)現(xiàn)的函數(shù)包括:
    • 帶T類型傳參的構(gòu)造函數(shù)
    • 拷貝構(gòu)造函數(shù)
    • 賦值構(gòu)造函數(shù)
    • 析構(gòu)函數(shù)
    • 解引用運(yùn)算符
    • ->運(yùn)算符
  • 需要擁有的成員變量:
    • 指向一個整型對象的指針
    • 指向一個T類型對象的指針
template<typename T>

class SharedPtr {

public:

        SharedPtr(T* p) :countPtr(new int(1)), point(p) {}

       SharedPtr(SharedPtr<T>& other) :countPtr(&(++*other.countPtr)), point(other.point) {}

       SharedPtr<T>& operator=(SharedPtr<T>& other) {

              ++* other.countPtr;

              if (this->_ptr && 0 == -- * this->countPtr) {

                     delete countPtr;

                     delete point;

              }

              this->countPtr = other.countPtr;

              this->point = other.point;

              return *this;

       }
       T& operator*() {

              return *point;

       }

       T* operator->() {

              return point;

       }

       ~SharedPtr() {

              if (-- * countPtr == 0) {

                     delete countPtr;

                     delete point;

              }

       }

private:

       int* countPtr;

       T* point;

};


std::make_shared和std::shared_ptr<T>(new T(args...))有啥區(qū)別吃型?

參考

  • 內(nèi)存分配次數(shù)
    • 內(nèi)存分配次數(shù)不同。(左:1次僚楞。右:2次)
  • 弱引用
    • 如果任何std::weak_ptr在所有共享所有者的生命周期結(jié)束后引用了std::make_shared創(chuàng)建的控制塊勤晚,T所占用的內(nèi)存將持續(xù)存在枉层,直到所有弱所有者也被銷毀,如果(T)的sizeof很大赐写,這可能是不可取的返干。
  • 公共構(gòu)造函數(shù)
    • 如果std::shared_ptr<T>(new T(args…))是在可訪問的上下文中執(zhí)行,可以調(diào)用T的非公共構(gòu)造函數(shù)血淌,而std::make_shared要求對所選構(gòu)造函數(shù)進(jìn)行公共訪問矩欠。
  • 刪除器
    • 與std::shared_ptr構(gòu)造函數(shù)不同,std::make_shared不允許自定義刪除器悠夯。
  • 操作符new癌淮。
    • std::make_shared使用::new,因此沦补,如果使用類特定的operator new設(shè)置了任何特殊行為乳蓄,它將不同于std::shared_ptr<T>(new T(args…))

RAII

  • 全稱為Resource Acquisition Is Initialization,中譯為:資源獲取就是初始化夕膀。C++標(biāo)準(zhǔn)保證任何情況下虚倒,已構(gòu)造的對象最終會銷毀,即它的析構(gòu)函數(shù)最終會被調(diào)用产舞。

野指針

  • 野指針是指針指向的位置是不可知的(隨機(jī)的魂奥、不正確的、沒有明確限制的)易猫。

  • 出現(xiàn)野指針的原因:
    • 未初始化
    • 指針?biāo)赶虻膶ο笠呀?jīng)釋放耻煤,但未將指針置為nullptr

#pragma once和#ifndef的區(qū)別

  • #ifndef的方式受C/C++語言標(biāo)準(zhǔn)支持。它不光可以保證同一個文件不會被包含多次准颓,也能保證內(nèi)容完全相同的兩個文件(或者代碼片段)不會被不小心同時包含哈蝇。
  • #pragma once一般由編譯器提供保證:同一個文件不會被包含多次∪烈眩——pragma的中文含義是編譯指示炮赦,在這個語句中指示編譯器只編譯一次該文件。

new和malloc

特征 new/delete malloc/free
分配內(nèi)存的位置 自由存儲區(qū)
內(nèi)存分配成功的返回值 完整類型指針 void*
內(nèi)存分配失敗的返回值 默認(rèn)拋出異常 返回NULL
分配內(nèi)存的大小 由編譯器根據(jù)類型計(jì)算得出 必須顯式指定字節(jié)數(shù)
處理數(shù)組 有處理數(shù)組的new版本new[] 需要用戶計(jì)算數(shù)組的大小后進(jìn)行內(nèi)存分配
已分配內(nèi)存的擴(kuò)充 無法直觀地處理样勃,可以用vector實(shí)現(xiàn) 使用realloc簡單完成
是否相互調(diào)用
分配內(nèi)存時內(nèi)存不足 客戶能夠指定處理函數(shù)或重新制定分配器 無法通過用戶代碼進(jìn)行處理
是否允許函數(shù)重載
是否調(diào)用構(gòu)造函數(shù)與析構(gòu)函數(shù)

內(nèi)存分區(qū)

名稱 作用
棧區(qū) 由編譯器自動分配釋放吠勘,存放為函數(shù)運(yùn)行的局部變量,函數(shù)參數(shù)彤灶,返回?cái)?shù)據(jù)看幼,返回地址等批旺。操作方式與數(shù)據(jù)結(jié)構(gòu)中的類似幌陕。
堆區(qū) 一般由程序員分配釋放,若程序員不釋放汽煮,程序結(jié)束時可能由OS回收搏熄。分配方式類似于鏈表棚唆。
全局?jǐn)?shù)據(jù)區(qū) 也叫做靜態(tài)區(qū),存放全局變量心例,靜態(tài)數(shù)據(jù)宵凌。程序結(jié)束后由系統(tǒng)釋放。
文字常量區(qū) 可以理解為常量區(qū)止后,常量字符串存放這里瞎惫。程序結(jié)束后由系統(tǒng)釋放。
程序代碼區(qū) 存放函數(shù)體的二進(jìn)制代碼译株。但是代碼區(qū)中也分為代碼段和數(shù)據(jù)段瓜喇。

堆和棧

不同點(diǎn)
管理方式 堆中資源由程序員控制(容易產(chǎn)生memory leak) 棧資源由編譯器自動管理,無需手工控制
系統(tǒng)響應(yīng) 對于堆歉糜,應(yīng)知道系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表乘寒,當(dāng)系統(tǒng)收到程序申請時,遍歷該鏈表匪补,尋找第一個空間大于申請空間的堆結(jié)點(diǎn)伞辛,刪除空閑結(jié)點(diǎn)鏈表中的該結(jié)點(diǎn),并將該結(jié)點(diǎn)空間分配給程序(大多數(shù)系統(tǒng)會在這塊內(nèi)存空間首地址記錄本次分配的大小夯缺,這樣delete才能正確釋放本內(nèi)存空間蚤氏,另外系統(tǒng)會將多余的部分重新放入空閑鏈表中) 對于棧,只要棧的剩余空間大于所申請空間踊兜,系統(tǒng)為程序提供內(nèi)存瞧捌,否則報(bào)異常提示棧出。
空間大小 堆是不連續(xù)的內(nèi)存區(qū)域(因?yàn)橄到y(tǒng)是用鏈表來存儲空閑內(nèi)存地址润文,自然不是連續(xù)的)姐呐,堆大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存(32bit 系統(tǒng)理論上是4G),所以堆的空間比較靈活典蝌,比較大曙砂。 棧是一塊連續(xù)的內(nèi)存區(qū)域,大小是操作系統(tǒng)預(yù)定好的骏掀,windows下棧大小是2M(也有是1M鸠澈,在 編譯時確定,VC中可設(shè)置)截驮。
碎片問題 對于堆笑陈,頻繁的new/delete會造成大量碎片,使程序效率降低葵袭。 對于棧涵妥,它是一個先進(jìn)后出的線性表,進(jìn)出一一對應(yīng)坡锡,不會產(chǎn)生碎片蓬网。
生長方向 堆向上窒所,向高地址方向增長。 棧向下帆锋,向低地址方向增長吵取。
分配方式 堆都是動態(tài)分配(沒有靜態(tài)分配的堆)。 棧有靜態(tài)分配和動態(tài)分配锯厢,靜態(tài)分配由編譯器完成(如局部變量分配)皮官,動態(tài)分配由alloca函數(shù)分配,但棧的動態(tài)分配的資源由編譯器進(jìn)行釋放实辑,無需程序員實(shí)現(xiàn)臣疑。
分配效率 堆由C/C++函數(shù)庫提供,機(jī)制很復(fù)雜徙菠。所以堆的效率比棧低很多讯沈。 棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)在底層對棧提供支持婿奔,分配專門寄存器存放棧地址缺狠,棧操作有專門指令。

內(nèi)存對齊的原因

  • 平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的萍摊;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù)挤茄,否則拋出硬件異常。
  • 性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊冰木。原因在于穷劈,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問踊沸;而對齊的內(nèi)存訪問僅需要一次訪問歇终。

Cast變換

  • C++為了規(guī)范C中的類型轉(zhuǎn)換,加強(qiáng)類型轉(zhuǎn)換的可視性,引入了以下四種類型轉(zhuǎn)換逼龟。
名稱 作用
const_cast 去除const(volatile)屬性评凝,將只讀變?yōu)榭勺x寫。
dynamic_cast 在進(jìn)行下行轉(zhuǎn)換時腺律,dynamic_cast具有類型檢查的功能奕短,彌補(bǔ)了static_cast類型不安全的缺陷,比static_cast更安全匀钧。
多用于有虛函數(shù)的基類與其派生類之間的轉(zhuǎn)換翎碑,特點(diǎn)是進(jìn)行運(yùn)行時檢測轉(zhuǎn)換類型是否安全,如果轉(zhuǎn)換失敗返回nullptr之斯,依賴于RTTI技術(shù)日杈,但是有額外的函數(shù)開銷。
static_cast 代替隱式轉(zhuǎn)換,基類與派生類的轉(zhuǎn)換达椰,派生類轉(zhuǎn)換成基類是安全的翰蠢,基類轉(zhuǎn)換成派生類是不安全的项乒。編譯期轉(zhuǎn)換啰劲。
reinterpret_cast 代替顯示轉(zhuǎn)換。

構(gòu)造函數(shù)有那些檀何?

  • 默認(rèn)構(gòu)造函數(shù)
  • 帶參數(shù)的構(gòu)造函數(shù)
  • 委托構(gòu)造函數(shù)
  • 拷貝構(gòu)造函數(shù)和拷貝賦值運(yùn)算符
  • 移動構(gòu)造函數(shù)和移動賦值運(yùn)算符

vector是不是線程安全的蝇裤?

參考

  • vector不是線程安全的,并發(fā)讀寫導(dǎo)致讀方的迭代器失效频鉴。

  • 處理線程安全的方法:

    • 加鎖栓辜。
    • 固定vector的大小。

shared_ptr是線程安全的嗎垛孔?

是藕甩,為了滿足線程安全需求,引用計(jì)數(shù)器通常使用std::atomic::fetch_add和std::memory_order_relaxed的等價遞增(遞減需要更強(qiáng)的順序來安全地銷毀控制塊)周荐。

std::map和std::unordered_map的實(shí)現(xiàn)原理

  • std::map:紅黑樹(一種特殊的平衡二叉樹)狭莱,特性如下:
    • 只有紅、黑兩種節(jié)點(diǎn)概作。
    • 根節(jié)點(diǎn)為黑節(jié)點(diǎn)腋妙。
    • 葉子節(jié)點(diǎn)為黑節(jié)點(diǎn),并且是nil節(jié)點(diǎn)讯榕。
    • 紅節(jié)點(diǎn)的子節(jié)點(diǎn)都是黑節(jié)點(diǎn)骤素。
    • 對于任意結(jié)點(diǎn)而言,其可達(dá)的葉子節(jié)點(diǎn)上的每條路徑都包含相同數(shù)目的黑結(jié)點(diǎn)愚屁。
  • std:unordered_map:哈希表济竹,哈希沖突的處理方式:
    • 采取鏈表的形式存儲相同哈希值的對象。
    • 根據(jù)負(fù)載因子來控制是否rehash來調(diào)整哈希表的表長霎槐。

std::condition_variable::wait為什么需要一個unique_lock<mutex>的變量lck规辱?

  • wait函數(shù)的實(shí)現(xiàn):
    • 執(zhí)行l(wèi)ck的unlock()方法(其他線程不再被阻塞
    • 沉睡等待喚醒
    • 其他線程調(diào)用了notify系列方法
    • 沉睡線程被喚醒,執(zhí)行l(wèi)ck.lock()

源代碼到可執(zhí)行程序過程

  • 預(yù)處理
    • 宏定義指令(#define)
    • 條件編譯指令(#ifdef)
    • 頭文件包含指令(#include)
    • 特殊符號(LINE栽燕、FILE)
  • 編譯
    • 語法分析罕袋,詞法分析,語義分析碍岔,符號匯總浴讯,然后生成匯編代碼文件
  • 匯編
    • 把匯編語言代碼翻譯成目標(biāo)機(jī)器指令
  • 鏈接
    • 將有關(guān)的目標(biāo)文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來蔼啦,使得所有的這些目標(biāo)文件成為一個能夠被操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體榆纽。

鎖的種類有那些?

  • 互斥鎖(std::mutex)
    • 可以避免多個線程在某一時刻同時操作一個共享資源,標(biāo)準(zhǔn)C++庫提供了std::unique_lock類模板奈籽,實(shí)現(xiàn)了互斥鎖的RAII慣用語法:
       std::unique_lock<std::mutex> lk(mtx_sync_);
  • 條件鎖(std::condition_variable)

    • 條件鎖等同于條件變量饥侵,某一個線程因?yàn)槟硞€條件未滿足時可以使用條件變量使該程序處于阻塞狀態(tài)。一旦條件滿足了衣屏,即可喚醒該線程(常和互斥鎖配合使用)躏升,喚醒后,需要檢查變量狼忱,避免虛假喚醒膨疏。
  • 讀寫鎖(std::shared_lock)

    • 也被稱作“共享-獨(dú)占鎖”,當(dāng)讀寫鎖以讀模式鎖住時钻弄,它是以共享模式鎖住的佃却;當(dāng)它以寫模式鎖住時,它是以獨(dú)占模式鎖住的窘俺。
  • 遞歸鎖(std::recursive_mutex)

    • std::recursive_mutex 允許同一個線程對互斥量多次上鎖(即遞歸上鎖)
  • 自旋鎖(spin_mutex)

    • 自旋鎖是一種基礎(chǔ)的同步原語饲帅,用于保障對共享數(shù)據(jù)的互斥訪問。與互斥鎖相比瘤泪,在獲取鎖失敗的時候不會使得線程阻塞而是一直自旋嘗試獲取鎖灶泵。當(dāng)線程等待自旋鎖的時候,CPU不能做其他事情均芽,而是一直處于輪詢忙等的狀態(tài)丘逸。自旋鎖主要適用于被持有時間短,線程不希望在重新調(diào)度上花過多時間的情況掀宋。
class spin_mutex {
       std::atomic<bool> flag = ATOMIC_VAR_INIT(false);
public:
       spin_mutex() = default;
       spin_mutex(const spin_mutex&) = delete;
       spin_mutex& operator= (const spin_mutex&) = delete;
       void lock() {
              bool expected = false;
              while (!flag.compare_exchange_strong(expected, true))
                     expected = false;
       }
       void unlock() {
              flag.store(false);
       }
}

C++與Lua的相互調(diào)用

Lua和C++ 交互機(jī)制的基礎(chǔ)在于Lua提供了一個虛擬棧深纲,C++ 和Lua之間的所有類型的數(shù)據(jù)交換都通過這個棧完成。無論何時C想從Lua中調(diào)用一個值劲妙,被請求的值將會被壓入棧湃鹊,無論何時C想要傳遞一個值給Lua,首先將整個值壓棧镣奋,然后就可以在Lua中調(diào)用币呵。

  • C++調(diào)用Lua:
    • 獲取Lua值:調(diào)用lua_getlocal獲取值->壓棧->調(diào)用該C API lua_toXXX將棧中元素取出轉(zhuǎn)成相應(yīng)的C類型的值
    • 調(diào)用Lua函數(shù):調(diào)用lua_getglobal獲取函數(shù)->壓棧->參數(shù)入棧->lua_pcall調(diào)用對應(yīng)函數(shù)->返回值入棧
  • Lua調(diào)用C++:
    • 包裝成Lua_CFunction->調(diào)用lua_register完成注冊->根據(jù)注冊名調(diào)用

生產(chǎn)者和消費(fèi)者簡易實(shí)現(xiàn)

參考

條件變量和互斥鎖(C++11)

#include <iostream>           
#include <queue>
#include <thread>             
#include <mutex> 
#include <condition_variable> 
using namespace std;

mutex mtx;
condition_variable produce, consume;  // 條件變量是一種同步機(jī)制,要和mutex以及l(fā)ock一起使用

queue<int> q;     // shared value by producers and consumers, which is the critical section
int maxSize = 20;

void consumer()
{
    while (true)
    {
        this_thread::sleep_for(chrono::milliseconds(1000));
        unique_lock<mutex> lck(mtx);
        consume.wait(lck, [] {return q.size() != 0; });     // wait(block) consumer until q.size() != 0 is true

        cout << "consumer " << this_thread::get_id() << ": ";
        q.pop();
        cout << q.size() << '\n';

        produce.notify_all();                               // nodity(wake up) producer when q.size() != maxSize is true
    }
}

void producer(int id)
{
    while (true)
    {
        this_thread::sleep_for(chrono::milliseconds(1000));      // producer is a little faster than consumer  
        unique_lock<mutex> lck(mtx);
         produce.wait(lck, [] {return q.size() != maxSize; });   // wait(block) producer until q.size() != maxSize is true

        cout << "producer " << this_thread::get_id() << ": ";
        q.push(id);
        cout << q.size() << '\n';

        consume.notify_all();                                   // notify(wake up) consumer when q.size() != 0 is true
    }
}

int main()
{
    thread consumers[2], producers[2];

    // spawn 2 consumers and 2 producers:
    for (int i = 0; i < 2; ++i)
    {
        consumers[i] = thread(consumer);
        producers[i] = thread(producer, i + 1);  //thread:第一個參數(shù)是task任務(wù)侨颈,第二個參數(shù)是task函數(shù)的參數(shù) 
    }

    // join them back: (in this program, never join...)
    for (int i = 0; i < 2; ++i)
    {
        producers[i].join();
        consumers[i].join();
    }

    system("pause");
    return 0;
}

信號量(C++20)

#include <iostream>           
#include <queue>
#include <thread>             
#include <semaphore>
using namespace std;

queue<int> q;     // shared value by producers and consumers, which is the critical section
int maxSize = 20;

counting_semaphore semaphore(0);

void consumer()
{
    while (true)
    {
        this_thread::sleep_for(chrono::milliseconds(1000));
        semaphore.acquire();

        cout << "consumer " << this_thread::get_id() << ":";
        q.pop();
        cout << q.size() << '\n';
    }
}

void producer(int id)
{
    while (true)
    {
        this_thread::sleep_for(chrono::milliseconds(1000));      // producer is a little faster than consumer  
        
        cout << "producer " << this_thread::get_id() << ":";
        q.push(id);
        cout << q.size() << '\n';
        semaphore.release();
    }
}

int main()
{
    thread consumers[2], producers[2];

    // spawn 2 consumers and 2 producers:
    for (int i = 0; i < 2; ++i)
    {
        consumers[i] = thread(consumer);
        producers[i] = thread(producer, i + 1);  //thread:第一個參數(shù)是task任務(wù)余赢,第二個參數(shù)是task函數(shù)的參數(shù) 
    }

    // join them back: (in this program, never join...)
    for (int i = 0; i < 2; ++i)
    {
        producers[i].join();
        consumers[i].join();
    }

    system("pause");
    return 0;
}

無鎖隊(duì)列

參考

  • 重要思想(CAS)

CAS是英文單詞Compare and Swap的縮寫,翻譯過來就是比較并替換哈垢。
CAS機(jī)制中使用了3個基本操作數(shù):內(nèi)存地址V妻柒,舊的預(yù)期值A(chǔ),要修改的新值B耘分。
更新一個變量的時候举塔,只有當(dāng)變量的預(yù)期值A(chǔ)和內(nèi)存地址V當(dāng)中的實(shí)際值相同時绑警,才會將內(nèi)存地址V對應(yīng)的值修改為B。

  • 通過atomic類來實(shí)現(xiàn)

template偏特化

參考

template偏特化是相對于template全特化而言的央渣,即只特化了部分模板參數(shù)计盒。

  • 類模板偏特化
template <typename T, typename Allocator_T>
class MyVector {
public:
    MyVector() {
        std::cout << "Normal version." << std::endl;
    }
};

template <typename T>
class MyVector<T, DefaultAllocator> {
public:
    MyVector() {
        std::cout << "Partial version." << std::endl;
    }
};

  • 函數(shù)模板偏特化(C++20)
template <typename A, typename B>
void f(A a, B b) {
    std::cout << "Normal version." << std::endl;
}

template <typename A, typename B>
requires std::integral<B>
void f(A a, B b) {
    std::cout << "Partial version." << std::endl;
}

類的函數(shù)后面加一個const

意味著只能修改static或mutable成員。

左值和右值

  • glvalue:一個表達(dá)式芽丹,它的求值決定了一個對象或函數(shù)的標(biāo)識北启。
  • prvalue:求值的表達(dá)式。1.計(jì)算內(nèi)置操作符的操作數(shù)的值志衍。2.初始化一個對象暖庄。
    結(jié)果對象可能是一個變量聊替、一個由new創(chuàng)建的對象楼肪、臨時物化物或者它的一個成員。需注意惹悄,非void的丟棄表達(dá)式有一個結(jié)果對象(物化的臨時表達(dá)式) 春叫,此外,每個類和數(shù)組prvalue都有一個結(jié)果對象泣港,除非它是decltype的操作數(shù)暂殖。
  • xvalue:(一個“即將過期”的值)是glvalue的一種,它表示一個對象的資源可以被重用;

左值:是glvalue但不是xvalue当纱。
右值:是prvalue或者xvalue呛每。

可重入

可重入函數(shù)主要用于多任務(wù)環(huán)境中,一個可重入的函數(shù)簡單來說就是可以被中斷的函數(shù)坡氯,也就是說晨横,可以在這個函數(shù)執(zhí)行的任何時刻中斷它,轉(zhuǎn)入OS調(diào)度下去執(zhí)行另外一段代碼箫柳,而返回控制時不會出現(xiàn)什么錯誤手形。

C++17新特性

  • 類型擦除(std::any)






計(jì)算機(jī)網(wǎng)絡(luò)的八股文

OSI七層模型

  • 應(yīng)用層
    • 網(wǎng)絡(luò)服務(wù)與最終用戶的一個接口。
    • 協(xié)議有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP
    • 數(shù)據(jù)單元為:消息
  • 表示層
    • 數(shù)據(jù)的表示悯恍、安全库糠、壓縮。
    • 格式有涮毫,JPEG瞬欧、ASCll、EBCDIC罢防、加密格式等艘虎。
    • 數(shù)據(jù)單元為:消息
  • 會話層
    • 建立、管理篙梢、終止會話顷帖。
    • 對應(yīng)主機(jī)進(jìn)程美旧,指本地主機(jī)與遠(yuǎn)程主機(jī)正在進(jìn)行的會話。
    • 數(shù)據(jù)單元為:消息
  • 傳輸層
    • 定義傳輸數(shù)據(jù)的協(xié)議贬墩,端口號榴嗅,以及流控和差錯校驗(yàn)。
    • 協(xié)議有:TCP UDP陶舞,數(shù)據(jù)包一旦離開網(wǎng)卡即進(jìn)入網(wǎng)絡(luò)傳輸層嗽测。
    • 數(shù)據(jù)單元為:數(shù)據(jù)段
  • 網(wǎng)絡(luò)層
    • 進(jìn)行邏輯地址尋址,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇肿孵。
    • 協(xié)議有:ICMP IGMP IP(IPV4 IPV6)
    • 數(shù)據(jù)單元為:數(shù)據(jù)報(bào)
  • 數(shù)據(jù)鏈路層
    • 建立邏輯連接唠粥、進(jìn)行硬件地址尋址、差錯校驗(yàn)等功能停做。(由底層網(wǎng)絡(luò)定義協(xié)議)
    • 將比特組合成字節(jié)進(jìn)而組合成幀晤愧,用MAC地址訪問介質(zhì),錯誤發(fā)現(xiàn)但不能糾正蛉腌。
    • 數(shù)據(jù)單元為:幀
  • 物理層
    • 建立官份、維護(hù)、斷開物理連接烙丛。(由底層網(wǎng)絡(luò)定義協(xié)議)
    • 數(shù)據(jù)單元為:比特

http和https的區(qū)別

https 主要由兩部分組成:http + ssl / tls舅巷,也就是在 http 上又加了一層處理加密信息的模塊。服務(wù)端和客戶端的信息傳輸都會通過 tls 進(jìn)行加密河咽,所以傳輸?shù)臄?shù)據(jù)都是加密后的數(shù)據(jù)钠右。

  • https協(xié)議需要到CA申請證書,一般免費(fèi)證書較少忘蟹,因而需要一定費(fèi)用飒房。
  • http是超文本傳輸協(xié)議,信息是明文傳輸寒瓦,https則是具有安全性的ssl/tls加密傳輸協(xié)議情屹,所以https相對安全。
  • 連接方式和端口不同:
    • http:連接是無狀態(tài)的杂腰,端口是80垃你。
    • https:連接也是無狀態(tài)的没咙,不過存在身份驗(yàn)證環(huán)節(jié)舞骆,并且傳遞數(shù)據(jù)存在加密解密環(huán)節(jié),端口是443妇蛀。

https加密算法

參考

  • 對稱加密算法:
    ?需要對加密和解密使用相同密鑰的加密算法少辣。所謂對稱凌摄,就是采用這種加密方法的雙方使用方式用同樣的密鑰進(jìn)行加密和解密。密鑰是控制加密及解密過程的指令漓帅。算法是一組規(guī)則锨亏,規(guī)定如何進(jìn)行加密和解密痴怨。

  • 非對稱加密算法:
    ?非對稱加密算法需要兩個密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是一對器予,如果用公鑰對數(shù)據(jù)進(jìn)行加密浪藻,只有用對應(yīng)的私鑰才能解密。如果用公鑰對數(shù)據(jù)進(jìn)行加密乾翔,只有用對應(yīng)的私鑰才能解密爱葵。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€不同的密鑰,所以這種算法叫作非對稱加密算法反浓。

  • 散列/哈希算法:
    ?指把數(shù)據(jù)通過某種公開的算法變成固定長度的hash值萌丈,這個過程可以使用密鑰也可以不使用,這種加密算法是不可逆的雷则,也就是說不能從加密后的hash值解密還原成明文辆雾,因此,這種算法通常用于驗(yàn)證數(shù)據(jù)是否被篡改和數(shù)據(jù)是否一致巧婶。因?yàn)橥瑯拥拿魑募用芎蟮玫绞窍嗤膆ash值乾颁。典型的算法有MD5涂乌,SHA艺栈,Base64等

    TCP和UDP對比

差異點(diǎn) TCP UDP
包頭大小 20字節(jié) 8字節(jié)
是否基于連接
是否可靠
對系統(tǒng)資源的要求 較多 較少
速度 較慢 較快

TCP如何保證可靠性

  • 檢驗(yàn)和
  • 序列號/確認(rèn)應(yīng)答
  • 超時重傳
  • 最大消息長度
  • 滑動窗口控制
  • 擁塞控制
  • 等等

TCP三次握手和四次揮手

  • 三次握手:建立連接


    image.png
  • 四次揮手:斷開連接


    image.png

如何實(shí)現(xiàn)tcp擁塞控制?

參考

  • 慢開始算法
    • 擁塞窗口由初始大小為1湾盒,指數(shù)式增大到慢開始門限(ssthresh)或出現(xiàn)擁塞為止湿右。若增大到慢開始門限(ssthresh),便開始采取擁塞避免算法罚勾;若出現(xiàn)擁塞毅人,將慢開始門限(ssthresh)減半,并將擁塞窗口置為1尖殃,然后再采取慢開始算法丈莺。
  • 擁塞避免算法
    • 發(fā)送數(shù)據(jù)每得到接收方確認(rèn),擁塞窗口大小增1送丰。
  • 快重傳算法
    • 數(shù)據(jù)傳輸時(數(shù)據(jù)被分成報(bào)文缔俄,每個報(bào)文都有個序號),中間的一部分丟失接收方?jīng)]收到器躏,接收方連續(xù)接到后面的數(shù)據(jù)俐载,則發(fā)回對丟失前的數(shù)據(jù)的重復(fù)確認(rèn),這樣發(fā)送方就知道有部分?jǐn)?shù)據(jù)丟失了登失,于是從丟失處重傳數(shù)據(jù)遏佣。
  • 快恢復(fù)算法
    • 快恢復(fù)是與快重傳配合的算法,在發(fā)生數(shù)據(jù)丟失時揽浙,發(fā)送方收到接收方發(fā)回的三個重復(fù)確認(rèn)信息時状婶,就把每次傳輸?shù)臄?shù)據(jù)量減為原來的一半意敛,擁塞窗口也修改為這個值,然后又開始采取擁塞避免算法策略。

什么是tcp粘包膛虫?如何處理空闲?

  • tcp粘包就是指發(fā)送方發(fā)送的若干包數(shù)據(jù)到達(dá)接收方時粘成了一包,從接收緩沖區(qū)來看走敌,后一包數(shù)據(jù)的頭緊接著前一包數(shù)據(jù)的尾碴倾。
  • 處理方法:
    • 發(fā)送方關(guān)閉Nagle算法(用于自動連接許多的小緩沖器消息)。
    • 接收方應(yīng)用層格式化數(shù)據(jù)或顯示聲明數(shù)據(jù)長度掉丽。

網(wǎng)址輸入會發(fā)生什么跌榔?

  • DNS解析->基于TCP連接的HTTP請求->服務(wù)器處理請求->瀏覽器解析響應(yīng)數(shù)據(jù)后渲染頁面->關(guān)閉TCP連接

什么是DNS協(xié)議?

  • 全稱為Domain Name System捶障,中譯為域名系統(tǒng)僧须,端口為53。DNS一種可以將域名和IP地址相互映射的層次結(jié)構(gòu)的分布式數(shù)據(jù)庫系統(tǒng)项炼。

Protobuf Union

參考

Protobuf沒有提供union類型担平,如果希望使用union類型,可以采用enum和optional屬性定義的方式锭部。

為什么采用Protobuf暂论?

  • Protobuf優(yōu)點(diǎn)
    • 傳輸效率快(據(jù)說在數(shù)據(jù)量大的時候,傳輸效率比xml和json快10-20倍)拌禾,序列化后體積相比Json和XML很小取胎,支持跨平臺多語言,消息格式升級和兼容性還不錯湃窍,序列化反序列化速度很快闻蛀。
  • Protobuf缺點(diǎn)
    • 使用不太方便。

Protobuf Lua 的序列化和反序列化

  • 序列化:SerializeToString
  • 反序列化:ParseFromString






計(jì)算機(jī)操作系統(tǒng)的八股文

進(jìn)程和線程

  • 進(jìn)程:是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動您市,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位觉痛。程序是指令、數(shù)據(jù)及其組織形式的描述茵休,進(jìn)程是程序的實(shí)體薪棒。
  • 線程:CPU調(diào)度的最小單位,線程的特點(diǎn)就是在不需要獨(dú)立資源的情況下就可以運(yùn)行泽篮。

進(jìn)程間通信方式

  • 管道

    • 匿名管道是一種半雙工的通信方式盗尸,數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進(jìn)程間使用帽撑。進(jìn)程的親緣關(guān)系通常是指父子進(jìn)程關(guān)系泼各。
    • 有名管道也是半雙工的通信方式,但是它允許無親緣關(guān)系進(jìn)程間的通信亏拉。
  • 消息隊(duì)列

    • 消息隊(duì)列是由消息的鏈表扣蜻,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識符標(biāo)識逆巍。消息隊(duì)列克服了信號傳遞信息少、管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)莽使。
  • 信號

    • 信號是一種比較復(fù)雜的通信方式锐极,用于通知接收進(jìn)程某個事件已經(jīng)發(fā)生。
  • 信號量

    • 信號量是一個計(jì)數(shù)器芳肌,可以用來控制多個進(jìn)程對共享資源的訪問灵再。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時亿笤,其他進(jìn)程也訪問該資源翎迁。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段净薛。
  • 共享內(nèi)存

    • 共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問的內(nèi)存汪榔,這段共享內(nèi)存由一個進(jìn)程創(chuàng)建,但多個進(jìn)程都可以訪問肃拜。共享內(nèi)存是最快的 IPC 方式痴腌,它是針對其他進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計(jì)的。它往往與其他通信機(jī)制燃领,如信號量士聪,配合使用,來實(shí)現(xiàn)進(jìn)程間的同步和通信戚嗅。
  • 套接字

    • 套接字也是一種進(jìn)程間通信機(jī)制,與其他通信機(jī)制不同的是枢舶,它可用于不同設(shè)備及其間的進(jìn)程通信。

共享內(nèi)存實(shí)例

參考

  • Windows實(shí)例
    需注意字符集:使用多字節(jié)字符集
#include <windows.h>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main()
{
    string strMapName("ShareMemory");                // 內(nèi)存映射對象名稱
    string strComData("This is common data!");        // 共享內(nèi)存中的數(shù)據(jù)
    LPVOID pBuffer;                                    // 共享內(nèi)存指針

    // 首先試圖打開一個命名的內(nèi)存映射文件對象
    HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, strMapName.c_str());
    if (NULL == hMap)
    {    // 打開失敗替久,創(chuàng)建之
        hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,
                                   NULL,
                                   PAGE_READWRITE,
                                   0,
                                   strComData.length()+1,
                                   strMapName.c_str());
        // 映射對象的一個視圖凉泄,得到指向共享內(nèi)存的指針,設(shè)置里面的數(shù)據(jù)
        pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        strcpy((char*)pBuffer, strComData.c_str());
        cout << "寫入共享內(nèi)存數(shù)據(jù):" << (char *)pBuffer << endl;
    }
    else
    {    // 打開成功蚯根,映射對象的一個視圖后众,得到指向共享內(nèi)存的指針,顯示出里面的數(shù)據(jù)
        pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        cout << "讀取共享內(nèi)存數(shù)據(jù):" << (char *)pBuffer << endl;
    }

    getchar();            // 注意颅拦,進(jìn)程關(guān)閉后蒂誉,所有句柄自動關(guān)閉,所以要在這里暫停

    // 解除文件映射距帅,關(guān)閉內(nèi)存映射文件對象句柄
    ::UnmapViewOfFile(pBuffer);
    ::CloseHandle(hMap);
    system("pause");
    return 0;
}

參考

  • Linux實(shí)例

#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <vector>
#include <unistd.h>
#include <cstring>

#define KEY_OF_SHM 8888
#define TEXT_SIZE 1024

struct ShmDataStruct {
    int readable_;
    char text_[TEXT_SIZE];
};

using namespace std;

int main(){
    //獲取shm_id右锨,在不同進(jìn)程中這是唯一的,獲取和KEY有關(guān)
    int shm_id = shmget(KEY_OF_SHM, sizeof(struct ShmDataStruct), 0666 | IPC_CREAT);

    string strComData("This is common data!");        // 共享內(nèi)存中的數(shù)據(jù)
    void *addr_to_shm;                                  // 共享內(nèi)存指針

    struct ShmDataStruct *shm_data;
      //將addr_to_shm連接到系統(tǒng)分配的共享內(nèi)存碌秸,也就是將共享內(nèi)存(物理地址)掛到當(dāng)前進(jìn)程的內(nèi)存空間(虛擬地址)
    addr_to_shm = shmat(shm_id, (void*)0, 0);

     //將獲得的void*類型的轉(zhuǎn)為我們需要的data struct
    shm_data = (struct ShmDataStruct*)addr_to_shm;

    // char buffer[TEXT_SIZE];
    if(shm_data->readable_ == 0){
        shm_data->readable_ = 1;
        strncpy(shm_data->text_, strComData.c_str(), strComData.size());
         cout << "寫入共享內(nèi)存數(shù)據(jù):" << (char *)shm_data->text_ << endl;
    }
    else{
        
        cout << "讀取共享內(nèi)存數(shù)據(jù):" << (char *)shm_data->text_ << endl;
    }

    shm_data->readable_ = 1;

    getchar();            // 注意绍移,進(jìn)程關(guān)閉后悄窃,所有句柄自動關(guān)閉,所以要在這里暫停

    //把共享內(nèi)存從當(dāng)前進(jìn)程分離蹂窖,也就是將其從進(jìn)程內(nèi)存空間的頁表中除掉
    shmdt(addr_to_shm);

    //刪除共享內(nèi)存
    shmctl(shm_id, IPC_RMID, 0);
    exit(EXIT_SUCCESS);
    return 0;
}

線程間通信方式

參考

  • 兩個進(jìn)程間的線程通信等同于進(jìn)程通信轧抗。
  • 單個進(jìn)程間的線程通信:
    • 互斥鎖
    • 條件變量
    • 信號量
    • 讀寫鎖shared_lock。

多線程的應(yīng)用場景瞬测?

  • 多線程處理后臺任務(wù)
  • 多線程異步處理任務(wù)
  • 多線程分布式計(jì)算

協(xié)程

  • 類似于子例程横媚,與線程不同的是,從當(dāng)前協(xié)程切換到其他協(xié)程由當(dāng)前協(xié)程來控制月趟。

死鎖

  • 死鎖是指集合中的每一個進(jìn)程都在等待只能由本集合中的其他進(jìn)程才能引發(fā)的事件分唾。

  • 產(chǎn)生死鎖的四個條件:

    • 互斥
    • 請求和等待
    • 不剝奪
    • 環(huán)路等待
  • 死鎖避免:銀行家算法

  • 死鎖檢測:定時檢測、效率低時檢測狮斗、進(jìn)程等待時檢測绽乔。

  • 死鎖解除:撤銷或掛起一些進(jìn)程。

  • 開發(fā)中如何避免死鎖碳褒?

    • 采取原子操作
    • 利用局部變量的生命周期(RAII)
    • try_lock

物理地址和邏輯地址

  • 物理地址:加載到內(nèi)存地址寄存器中的地址折砸,內(nèi)存單元的真正地址。
  • 邏輯地址:CPU所生成的地址沙峻。

虛擬內(nèi)存

  • 虛擬內(nèi)存是計(jì)算機(jī)系統(tǒng)內(nèi)存管理的一種技術(shù)睦授。它使得應(yīng)用程序認(rèn)為它擁有連續(xù)的可用的內(nèi)存(一個連續(xù)完整的地址空間),而實(shí)際上摔寨,它通常是被分隔成多個物理內(nèi)存碎片去枷,還有部分暫時存儲在外部磁盤存儲器上,在需要時進(jìn)行數(shù)據(jù)交換是复。

作業(yè)調(diào)度策略

  • FIFO全稱為:First Come First Serve删顶,中譯為:先來先服務(wù)
  • SJF全稱為:Shortest Job First,中譯為:短作業(yè)優(yōu)先
  • 時間片輪轉(zhuǎn)
  • 多級反饋隊(duì)列
  • 高響應(yīng)比優(yōu)先

頁面置換算法

  • OPT全稱為:Optimal Replacement Algorithm淑廊,中譯為:最佳置換算法
  • FIFO全稱為:First In First Out逗余,中譯為:先進(jìn)先出置換算法
    • Belady現(xiàn)象:采用FIFO算法時,如果對—個進(jìn)程未分配它所要求的全部頁面季惩,有時就會出現(xiàn)分配的頁面數(shù)增多但缺頁率反而提高的異陈剂唬現(xiàn)象。
  • LRU全稱為:Least Recently Used画拾,中譯為:最近最久未使用置換算法

大端和小端

  • 大端:字?jǐn)?shù)據(jù)的高字節(jié)存儲在低地址中啥繁,字?jǐn)?shù)據(jù)的低字節(jié)則存放在高地址中。
  • 小端:字?jǐn)?shù)據(jù)的低字節(jié)存儲在低地址中青抛,字?jǐn)?shù)據(jù)的高字節(jié)則存放在高地址中旗闽。

孤兒進(jìn)程和僵尸進(jìn)程

  • 孤兒進(jìn)程:一個父進(jìn)程退出,而它的一個或多個子進(jìn)程還在運(yùn)行,那么那些子進(jìn)程將成為孤兒進(jìn)程宪睹。孤兒進(jìn)程將被init進(jìn)程(進(jìn)程號為1)所收養(yǎng)愁茁,并由init進(jìn)程對它們完成狀態(tài)收集工作。
  • 僵尸進(jìn)程:一個進(jìn)程使用fork創(chuàng)建子進(jìn)程亭病,如果子進(jìn)程退出鹅很,而父進(jìn)程并沒有調(diào)用wait或waitpid獲取子進(jìn)程的狀態(tài)信息,那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中罪帖。這種進(jìn)程稱之為僵尸進(jìn)程促煮。

進(jìn)程響應(yīng)信號有那些方式?

  • 忽略
  • 執(zhí)行默認(rèn)
  • 捕獲






數(shù)據(jù)結(jié)構(gòu)與算法的八股文

二叉樹的應(yīng)用場景

  • C++ STL中的set整袁、map菠齿,數(shù)據(jù)壓縮(哈夫曼編碼),海量數(shù)據(jù)并發(fā)查詢(平衡二叉樹)

用兩個小球來判斷100層高的樓會被摔壞的最低樓層

參考
參考

  • 采用動態(tài)規(guī)劃的思想
  • dp(n,2) = max(k,dp(n-k,2)+1)坐昙,dp(1,2) = 1 臨界點(diǎn):k == dp(n-k,2)+1
    *當(dāng)n == 1 + 2 + 3 + ... + k時绳匀,dp(n,2) = k。

最短路徑算法

  • 單源最短路徑算法:
    • Dijkstra算法(單源炸客、無負(fù)權(quán)疾棵、有向圖、無向圖最短路徑)
    • Bellman-Ford算法(單源痹仙、可有負(fù)權(quán)是尔、有向圖、無向圖最短路徑)
  • 多源最短路徑算法:
    • Floyd算法(多源开仰、可有負(fù)權(quán)拟枚、有向圖、無向圖最短路徑)






計(jì)算機(jī)操作系統(tǒng)的八股文

簡述CPU執(zhí)行一條指令的過程

  • 取指令階段:將一條指令從主存中取到指令寄存器的過程众弓。
  • 指令譯碼階段:在指令譯碼階段恩溅,指令譯碼器按照預(yù)定的指令格式,對取回的指令進(jìn)行拆分和解釋田轧,識別區(qū)分出不同的指令類別以及各種獲取操作數(shù)的方法暴匠。
  • 執(zhí)行指令階段:此階段的任務(wù)是完成指令所規(guī)定的各種操作,具體實(shí)現(xiàn)指令的功能傻粘。為此,CPU的不同部分被連接起來帮掉,以執(zhí)行所需的操作弦悉。
  • 訪存取數(shù)階段:根據(jù)指令地址碼,得到操作數(shù)在主存中的地址蟆炊,并從主存中讀取該操作數(shù)用于運(yùn)算稽莉。
  • 結(jié)果寫回階段:把執(zhí)行指令階段的運(yùn)行結(jié)果數(shù)據(jù)“寫回”到某種存儲形式。

頁面分頁和分段的不同點(diǎn)

  • 頁是信息的物理單位涩搓,分頁是為實(shí)現(xiàn)離散分配方式污秆,以消減內(nèi)存的外零頭劈猪,提高內(nèi)存的利用率;或者說良拼,分頁僅僅是由于系統(tǒng)管理的需要战得,而不是用戶的需要。
    段是信息的邏輯單位庸推,它含有一組其意義相對完整的信息常侦。分段的目的是為了能更好的滿足用戶的需要。
  • 頁的大小固定且由系統(tǒng)確定贬媒,把邏輯地址劃分為頁號和頁內(nèi)地址兩部分聋亡,是由機(jī)器硬件實(shí)現(xiàn)的,因而一個系統(tǒng)只能有一種大小的頁面际乘。
    段的長度卻不固定坡倔,決定于用戶所編寫的程序,通常由編輯程序在對源程序進(jìn)行編輯時脖含,根據(jù)信息的性質(zhì)來劃分罪塔。
  • 分頁的作業(yè)地址空間是維一的,即單一的線性空間器赞,程序員只須利用一個記憶符垢袱,即可表示一地址。
    分段的作業(yè)地址空間是二維的港柜,程序員在標(biāo)識一個地址時请契,既需給出段名,又需給出段內(nèi)地址夏醉。

未完待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爽锥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子畔柔,更是在濱河造成了極大的恐慌氯夷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶擦,死亡現(xiàn)場離奇詭異腮考,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)玄捕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門踩蔚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枚粘,你說我怎么就攤上這事馅闽。” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵福也,是天一觀的道長局骤。 經(jīng)常有香客問我,道長暴凑,這世上最難降的妖魔是什么峦甩? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮搬设,結(jié)果婚禮上穴店,老公的妹妹穿的比我還像新娘。我一直安慰自己拿穴,他們只是感情好泣洞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著默色,像睡著了一般球凰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腿宰,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天呕诉,我揣著相機(jī)與錄音,去河邊找鬼吃度。 笑死甩挫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的椿每。 我是一名探鬼主播伊者,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼间护!你這毒婦竟也來了亦渗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤汁尺,失蹤者是張志新(化名)和其女友劉穎法精,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痴突,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搂蜓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了辽装。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洛勉。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖如迟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤殷勘,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布此再,位于F島的核電站,受9級特大地震影響玲销,放射性物質(zhì)發(fā)生泄漏输拇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一贤斜、第九天 我趴在偏房一處隱蔽的房頂上張望策吠。 院中可真熱鬧,春花似錦瘩绒、人聲如沸猴抹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟀给。三九已至,卻和暖如春阳堕,著一層夾襖步出監(jiān)牢的瞬間跋理,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工恬总, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留前普,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓壹堰,卻偏偏與公主長得像拭卿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缀旁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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