操作系統知識(筆記)

進程、線程

進程(process)和線程(thread)的區別?

進程和線程本質上都是CPU的一個工作時間段,進程包括了CPU加載程序上下文、CPU執行、CPU保存程序上下文。線程包含在進程中,一個進程至少有一個線程,也可以有多個線程,進程的不同線程之間共享CPU和程序上下文。
進程是操作系統資源分配(包括CPU、內存、磁盤IO等)的最小單元;線程是CPU調度和分配的基本單元,是最小的執行單元。
PS:不同進程之間的連續虛擬地址空間被MMU映射到不同的離散物理地址,因此不同進程間的用戶空間的數據是不共享的。此外,內核空間的代碼和數據是不同進程之間共享的。

協程(coroutine),協同程序?

協程又稱微線程,是一段子程序。在執行過程中,子程序內部可以中斷,然後轉而執行別的子程序,在適當的時候再返回來接着執行。(在一個子程序中中斷,去執行其他子程序,不是函數調用!)
協程是子程序的切換而不是線程的切換,和多線程相比,節省了線程切換的開銷,執行效率高。
PS:協程切換完全在用戶態進行,它的開銷只有切換CPU上下文;線程切換隻有最高權限的內核態才能完成,它的開銷除了CPU上下文切換,還有用戶態和內核態的切換的開銷以及線程調度算法完成線程調度的開銷。
PS:多線程+協程,即充分用多核,又充分發揮協程的高效率,可以獲得極高的性能。

生產者消費者模式?

生產者和消費者問題是線程模型的經典問題:生產者和消費者在同一時間段內共用同一個存儲空間,生產者往存儲空間中添加產品,消費者從存儲空間中取走產品,當存儲空間爲空時,消費者阻塞,當存儲空間滿時,生產者阻塞
單生產者-單消費者:緩存隊列+互斥量+條件變量實現。(隊列模擬存儲空間;互斥量保證多個讀寫線程之間互斥;條件變量保證隊列爲空時消費者線程會被阻塞,等待隊列非空,隊列爲滿時生產者線程會被組設,等待隊列非滿) -> 應用場景:緩存IO(如TCP套接字的緩衝區)
簡單的實現:
維護兩個位置變量和條件變量:

size_t read_pos; // 消費者讀取產品位置.
size_t write_pos; // 生產者寫入產品位置.
std::mutex mtx; // 互斥量,保護產品緩衝區
std::condition_variable repo_not_full; // 條件變量, 指示產品緩衝區不爲滿.
std::condition_variable repo_not_empty; // 條件變量, 指示產品緩衝區不爲空.

當(write_pos+1)%repository_size == read_pos時表明隊列已滿,要阻塞生產。(repository_size爲存儲空間(緩存)的大小)

...
while(((ir->write_pos + 1) % repository_size) == ir->read_pos) { 
// item buffer is full, just wait here.
    (ir->repo_not_full).wait(lock); // 生產者等待"產品庫緩衝區不爲滿"這一條件發生.
}
... // 寫入產品,寫入位置後移
(ir->repo_not_empty).notify_all(); // 通知消費者產品庫不爲空.

當write_pos == read_pos時,表明隊列爲空,需要阻塞消費者。

...
while(ir->write_pos == ir->read_pos) {
// item buffer is empty, just wait here
    (ir->repo_not_empty).wait(lock); // 消費者等待"產品庫緩衝區不爲空"這一條件發生.
}
... // 讀取產品,讀取位置後移
(ir->repo_not_full).notify_all(); // 通知消費者產品庫不爲滿.

多生產者-多消費者:需要額外維護消費者取走產品的計數器和生產者放入產品的計數器,用於判斷程序是否要結束。
PS:生產者消費者模式還可以用協程實現。改用協程,生產者生產消息後,直接通過yield 跳轉到消費者開始執行,待消費者執行完畢後,切換回生產者繼續生產,效率極高。(參考博客
協程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章