(1) Unix基礎知識: 內核->系統調用->shell和庫函數->應用軟件html
(2) 文件I/O:read函數返回值、進程的文件描述符表、文件共享、inode、fcntl函數node
(3) 文件和目錄:文件類型(普通、目錄、socket、FIFO、PIPE)、文件系統(硬連接、軟連接)linux
(4) 標準I/O庫:FIFE封裝、最佳緩衝大小測試c++
(5) 進程環境:進程終止狀況、longjmp、volatile用法程序員
(6) 進程控制:fork(返回值、父子進程的文件描述符表)、wait函數、exec系函數算法
(7) 信號:三種處理方式、常見信號(SIGCHLD、SIGSEGV)及其默認處理方式shell
(8) 線程同步:進程和線程的異同點、線程回調函數的傳參、進程和線程原語對比、線程同步(讀寫、寫寫、i++多線程、mutex)編程
(9) 高級I/O(一):非阻塞I/O、select使用、readn和writen封裝、mmap映射數組
(10) 高級I/O(二):管道、消息隊列、共享存儲器mmap緩存
(11) 網絡套接字:大小端字節序、addrinfo結構體、getaddrinfo函數、tcp_listen和tcp_connect封裝
(1) 系統調用、API和ABI、文件(各類類型簡介、inode、軟連接、硬連接)、進程簡介
(2) 文件I/O:read函數返回值、readn和writen函數封裝、文件定位、文件同步、文件截斷、多路I/O(select、poll)、Linux內核實現
(3) 標準I/O緩衝:測試最佳I/O緩衝區大小、三種類型緩衝、標準I/O的線程安全、標準I/O的缺點
(4) 高級I/O:彙集I/O(readv、writev性能好、原子性)、epoll(LT和ET)、mmap(優缺點)、I/O調度算法(電梯調度)
(5) 進程管理:進程pid分配方法、fork and exec、copy on write、wait、殭屍進程的回收
(6) 進程調度:Linux進程調度算法(FIFO、最短優先、時間片輪轉)、CPU綁定(緩存影響)
(7) 線程:虛擬化抽象(虛擬內存與進程關聯、虛擬處理器與線程關聯)、多線程好處、多線程i++解析、pthread使用、RAII封裝mutex
(8) 文件和目錄管理:文件inode節點元數據、目錄操做、軟連接和硬連接、塊設備/dev/null
(9) 內存管理:進程地址空間、動態分配內存(malloc、calloc、brk)、數據對齊、匿名文件映射、變長數組
(10) 信號:信號的3中處理方式、常見的信號
(11) 時間:gettimeofday、sleep休眠、定時器alarm
字節序問題:
大端:地址爲 閱讀順序:Sun系統 和 網絡字節序
小端:地址爲 逆閱讀序:X86
信息 = Bit位 + 解釋方式,不管怎麼轉換,Bit位是永遠不變的,只有解釋方式改變了
對於int的使用,參見:Google c++編程規範中int型使用
C語言整型溢出問題by @左耳朵耗子
儘可能不要使用無符號數,極易bug:當執行一個運算時,若是一個運算數是有符號的而另外一個是無符號的,那麼c語言會隱式地將有符號數強制類型轉換爲無符號數
好比:函數參數類型爲size_t, 我傳入實參-1,這時-1會隱式的 轉換爲 最大正數,徹底錯了
結構體數據對齊有2個原則:
(1) 每一個成員數據的偏移 必須是 該數據類型大小的整數倍
(2) 整個結構體大小 必須是 最大數據類型大小的 整數倍
數據對齊產生了 內部碎片,爲了使內部碎片最小,必須讓 最大的數據類型擺放在最前面
如何計算 每一個成員數據在結構體內的偏移呢? C語言提供 offsetof宏
#define offsetof(type, member) (size_t)&(((type*)0)->member)
struct test { int val; int a[2]; }; // 結構體訪問和數組訪問的實質都是 首地址加上對應偏移,而後讀取對應數據,注意 取地址 和 取成員 操做的區別 struct test* ptest = NULL; // 結構體首地址爲0 fprintf(stdout, "1:%p\n", &ptest->val); // 注意:這是讀取 結構體成員數據的偏移,直接就是 首地址加上 offset,而不是 先取到數據而後取地址 fprintf(stdout, "2:%d\n", ptest->val); // 錯誤,能夠打印地址0的地址值,可是不能訪問地址值爲0的數據 fprintf(stdout, "3:%p\n", &ptest->a); // 正確,首地址加上offset fprintf(stdout, "4:%p\n", ptest->a); // 同上,數組名退化爲 數組首地址,因此這仍是一個取地址操做
具體詳見:C語言結構體內的數組和指針by@左耳朵耗子
CPU Cache示例by@左耳朵耗子
C語言數組行優先存儲,當數組大小超過 緩存塊大小時,不一樣的存取方式之間 差異很大,以 A[N][N] * B[N][N] 存儲在 C[N][N]中
靜態編譯和動態編譯
詳見陳碩的 <C++編譯連接模型精要>
連接器主要完成兩件事:
(1) 符號解析:將每一個符號的引用(reference)對應到相應符號的定義(definition)
C程序員應該儘量使用static屬性在模塊內部隱藏變量和函數聲明,即模塊私有
注:使用 readelf命令來查看目標文件的符號表
當linker遇到重名時:
重名Local定義:編譯器解決
重名Global定義:強符號(函數名和已初始化的全局變量)和弱符號(未初始化的全局變量)
(2) 重定位:合併不一樣文件時修改符號地址,將符號的相對地址 改成 絕對地址
Linux系統爲動態連接庫提供了一個簡單的接口,容許應用程序在運行時加載和連接共享庫
#include <dlfcn.h> void* dlopen(const char* filename, int flag); // dlopen函數加載和連接共享庫filename void* dlsym(void* handle, char* symbol); // dlsym函數的輸入參數爲dlopen打開的共享庫句柄和符號名,返回符號的地址 int dlclose(void* handle);
(1) 管道、FIFO(命名管道)
管道:管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程關係
FIFO:有名管道也是半雙工的通訊方式,可是它容許無親緣關係進程間的通訊。
(2) 信號(Signal)
信號用於通知接受進程有某種事件發生,除了用於進程間通訊外,進程還能夠發送信號給進程自己;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD爲了實現可靠信號機制,又可以統一對外接口,用sigaction函數從新實現了signal函數)
(3) 報文(Message)隊列(消息隊列)
消息隊列是消息的連接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程能夠向隊列中添加消息,被賦予讀權限的進程則能夠讀走隊列中的消息。消息隊列克服了信號承載信息量少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
(4) 信號量(semaphore)
主要做爲進程間以及同一進程不一樣線程之間的同步手段,是一個計數器,用於多進程對共享數據對象的訪問
(5) 共享內存
共享內存就是映射一段能被其餘進程所訪問的內存,這段共享內存由一個進程建立,但多個進程均可以訪問
共享內存是最快的 IPC 方式(由於數據不須要在客戶進程和服務器進程之間複製)
使用mmap進行文件內存映射 和 匿名存儲映射(將fd設爲-1)
(6) socket套接字
套接字接口既能夠用於多機之間進程通訊,也能夠用於單機內部進程通訊
(1) 互斥鎖
(2) 條件變量
(3) 讀寫鎖