進程線程協(xié)程區(qū)別
定義上
- 進程:資源分配和擁有的基本單位,是調(diào)度的基本單位。運行一個可執(zhí)行程序會創(chuàng)建一個或者多個進程;進程就是運行起來的程序
- 線程:程序執(zhí)行基本單位,輕量級進程。每個進程中都有唯一的主線程,主線程和進程是相互依賴的關(guān)系。
- 協(xié)程:用戶態(tài)的輕量級線程,線程內(nèi)部調(diào)度的基本單位
切換情況
- 進程:操作系統(tǒng)切換;從用戶態(tài)到內(nèi)核態(tài)再到用戶態(tài);進程CPU環(huán)境(棧(內(nèi)核棧)、寄存器、頁表和文件句柄等)保存;新調(diào)度的進程CPU環(huán)境設(shè)置
- 線程:操作系統(tǒng)切換;從用戶態(tài)到內(nèi)核態(tài)再到用戶態(tài);保存和設(shè)置程序計數(shù)器、少量寄存器和棧(內(nèi)核棧)的內(nèi)容
- 協(xié)程:用戶切換;一直在用戶態(tài);保存寄存器上下文和棧(用戶棧)
擁有資源
- 進程:CPU、內(nèi)存、文件和句柄
- 線程: 程序計數(shù)器、寄存器、狀態(tài)字、棧 (線程棧和棧指針)。
同一線程共享堆、全局變量、靜態(tài)變量、指針、引用、文件等,而獨自擁有棧。線程不擁有系統(tǒng)資源,但是一個進程的多個線程可以共享隸屬進程的資源。
- 協(xié)程:自己的寄存器上下文和棧
并發(fā)性
- 進程:不同進程實現(xiàn)并發(fā),各自占有CPU實現(xiàn)并行
- 線程:一個進程內(nèi)部多個線程并發(fā)執(zhí)行(最好和CPU核數(shù)相等)
- 協(xié)程: 同一個時間只能執(zhí)行一個協(xié)程
系統(tǒng)開銷
- 進程:開銷很大,切換虛擬地址空間、內(nèi)核棧、硬件上下文,CPU高速緩存失效、頁表切換開銷都很大
- 線程:保存和設(shè)置少量寄存器內(nèi)容,開銷很小
- 協(xié)程:直接操作棧則基本沒有內(nèi)核切換的開銷,可以不加鎖地訪問全局變量,所以上下文切換非???/li>
通信
- 進程: 需要借助操作系統(tǒng)
- 線程:可以直接讀寫進程數(shù)據(jù)段(比如全局變量)來進行通信。
- 協(xié)程:共享內(nèi)存、消息隊列
使用以及開銷
- 線程使用有一定的難度,需要處理數(shù)據(jù)一致性 的問題
- 進程創(chuàng)建和銷毀需要重新分配、銷毀task_struct結(jié)構(gòu);線程創(chuàng)建和銷毀只需要處理PC值、狀態(tài)碼、通用寄存器值、線程棧和棧指針即可。
-
Linux內(nèi)核通過一個被稱為進程描述符的task_struct結(jié)構(gòu)體來管理進程,這個結(jié)構(gòu)體包含了一個進程所需的所有信息。這個結(jié)構(gòu)體存放在叫做任務(wù)列表的雙向循環(huán)鏈表中。系統(tǒng)中每一個進程/線程的PCB都是由這個雙向鏈表來管理的
一個進程可以創(chuàng)建多少個線程?
無用線程要及時銷毀,不然過多的線程將會導(dǎo)致大量的時間浪費在線程切換上,給程序運行效率帶來負(fù)面影響。
參考一個進程最多可以創(chuàng)建多少個線程?
這與兩個方面有關(guān)系:
- 進程的虛擬內(nèi)存空間上限:創(chuàng)建以個線程,操作系統(tǒng)就需要為其分配一個??臻g,如果線程數(shù)量越多,所需要的??臻g就越大,那么虛擬內(nèi)存就會占用的越多。
- 系統(tǒng)參數(shù)限制 :雖然Linux沒有內(nèi)核參數(shù)來控制單個進程創(chuàng)建的最大線程個數(shù),但是有系統(tǒng)級別的參數(shù)來控制整個系統(tǒng)的最大線程數(shù)。
32位
假設(shè)創(chuàng)建一個線程需要占用10M的虛擬內(nèi)內(nèi)存,總共有3G虛擬內(nèi)存可以使用,于是差不多可以創(chuàng)建300個左右的線程。如果想創(chuàng)建上千個線程,可以調(diào)整**創(chuàng)建線程時分配的??臻g大小比如調(diào)整成512K。ulimit -s 512
64位
64位系統(tǒng)如果按照上面的方法來計算可以創(chuàng)建的線程數(shù)量,會發(fā)現(xiàn)可以創(chuàng)建一千多萬個線程,這明顯是不可能的,因為還有系統(tǒng)的限制。(還會有CPU瓶頸問題)
下面這三個參數(shù)都會影響線程創(chuàng)建的上限:
/proc/sys/kernel/threads-max,表示系統(tǒng)支持的最大線程數(shù),默認(rèn)值是 14553;
/proc/sys/kernel/pid_max,表示系統(tǒng)全局的 PID 號數(shù)值的限制,每一個進程或線程都有 ID,ID 的值超過這個數(shù),進程或線程就會創(chuàng)建失敗,默認(rèn)值是 32768;
/proc/sys/vm/max_map_count,表示限制一個進程可以擁有的VMA(虛擬內(nèi)存區(qū)域)的數(shù)量,具體什么意思我也沒搞清楚,反正如果它的值很小,也會導(dǎo)致創(chuàng)建線程失敗,默認(rèn)值是 65530。
多進程和多線程
多進程
每一個進程是資源分配的基本單位。
- 進程結(jié)構(gòu)由代碼段、堆棧段、數(shù)據(jù)段組成。代碼段是靜態(tài)的二進制代碼,多個程序可以共享。
父子進程
父進程創(chuàng)建子進程之后,除了pid之外幾乎全部都一樣。共享全部數(shù)據(jù),但是子進程在讀寫數(shù)據(jù)的時候會通過寫時復(fù)制機制將公共數(shù)據(jù)重新拷貝一份,然后再拷貝的數(shù)據(jù)上進行操作
如果子進程想要運行自己的代碼段,可以通過調(diào)用execv()函數(shù)重新加載新的代碼段,然后就和父進程獨立開了。(在shell中執(zhí)行程序就是通過shell進程先fork一個子進程然后通過execv()重新加載新的代碼段的過程)
進程創(chuàng)建方式
整個Linux系統(tǒng)的所有進程也是一個樹形結(jié)構(gòu),樹根是由系統(tǒng)自動構(gòu)造的,即在內(nèi)核態(tài)執(zhí)行的0號進程,它是所有進程的祖先。
第一種方式
參考Linux中的0號進程和1號進程
由0號進程創(chuàng)建1號進程(內(nèi)核態(tài)),1號負(fù)責(zé)執(zhí)行內(nèi)核部分初始化工作以及進行系統(tǒng)配置,并創(chuàng)建若干個用于高速緩存和虛擬主存管理的內(nèi)核線程,隨后1號調(diào)用execve()運行可執(zhí)行程序init,并演變成用戶態(tài)1號(init進程)。它按照配置文件/etc/initab的要求,完成系統(tǒng)啟動工作,創(chuàng)建編號為1號、2號的若干終端注冊進程Getty。每個Getty進程設(shè)置其進程標(biāo)識號,并監(jiān)視配置到系統(tǒng)終端 的接口線路,當(dāng)檢測到來自終端的連接信號時,getty進程通過函數(shù)evecve()執(zhí)行注冊程序login,此時用戶就可以輸入注冊名和密碼進入登錄過程,如果成功,由login程序再通過函數(shù)execv()執(zhí)行shell,該shell進程接收getty進程的pid,取代原來的getty進程。再由shell進程直接或者間接產(chǎn)生其他進程。
1號內(nèi)核進程調(diào)用執(zhí)行init并且演變成1號用戶態(tài)進程(init進程),這里前者是init是函數(shù),后者是進程。
init()函數(shù)在內(nèi)核態(tài)運行,是內(nèi)核代碼;init()進程是內(nèi)核啟動并運行的第一個用戶進程,運行在用戶態(tài)下
1號進程調(diào)用execve()從文件/etc/inittab中加載可執(zhí)行程序init()并執(zhí)行,這個過程沒有調(diào)用do_fork(),因此兩個都是1號進程。
第二種方式
父進程創(chuàng)建
進程退出
正常退出
- exit()和__exit(),都會進行終止進程并做收尾工作,但是后者關(guān)閉全部描述符和清理函數(shù)之后不會刷新流,但是前者會在調(diào)用__exit()之前刷新數(shù)據(jù)流
- return:exit()是函數(shù),有參數(shù),執(zhí)行完之后控制權(quán)交給系統(tǒng)。return若是在調(diào)用函數(shù)中,執(zhí)行完之后控制權(quán)交給調(diào)用進程,若是在main函數(shù)中,控制權(quán)交給系統(tǒng)。
異常退出
abort(),終止信號
多線程
同一個進程內(nèi)部有多個線程,所有線程共享同一個進程的內(nèi)存空間,進程中定義的全局變量會被所有的線程共享,多個線程被CPU調(diào)度的順序是不可控的所以對臨界資源的訪問要注意安全。
做一次簡單的i=i+1在計算機中不是原子操作,涉及內(nèi)存取數(shù)、計算和寫入內(nèi)存幾個環(huán)節(jié)。而線程切換有可能發(fā)生在上述任何一個環(huán)節(jié)中間,所以不同操作順序有可能帶來意想不到的結(jié)果。
多線程的優(yōu)點
會使原先順序執(zhí)行的程序被拆分成幾個獨立的邏輯流,可以獨立完成一些任務(wù)
使用多線程應(yīng)該注意的問題
- 線程是否有先后訪問順序
- 多個線程共享訪問同一個變量(同步互斥問題)
每個線程是有自己獨立的??臻g的,線程彼此之間是無法訪問其他線程棧上內(nèi)容的
什么時候使用多線程?什么時候使用多進程?
多線程
- 頻繁修改
- 需要大量計算,因為需要消耗大量CPU資源并且切換頻繁
- 任務(wù)間相關(guān)性比較強的用多線程
- 可能要擴展到多核分布的
多進程
可能要擴展到多機分布的
Linux進程控制
虛擬地址空間
虛擬存儲器為每個進程提供了獨占系統(tǒng)地址空間的假象。好像每個進程都在獨占地使用主存。每個進程看到的存儲器都是一致的,稱之為虛擬地址空間。
有一些敏感的地址:對于32位進程來說,代碼段從0X08048000開始,從0XC0000000開始到0XFFFFFFFF是內(nèi)核地址空間,通常情況下代碼運行在用戶態(tài)(0X00000000~0XC0000000的用戶地址空間),當(dāng)發(fā)生系統(tǒng)調(diào)用、進程切換等操作時CPU控制寄存器設(shè)置模式位,進入內(nèi)核模式,這個狀態(tài)下進程可以訪問全部存儲器位置和執(zhí)行全部指令。(32位進程地址空間都是4G,但是用戶態(tài)下只能訪問低3G的地址空間,若要訪問3G到4G的地址空間則要進入內(nèi)核態(tài))
PCB
進程調(diào)度實際上就是內(nèi)核選擇響應(yīng)的進程控制塊,被選擇的進程控制塊中包含了一個進程基本信息(進程標(biāo)識符、處理及狀態(tài)、進程調(diào)度信息、進程控制信息)
上下文切換
內(nèi)核管理所有進程控制塊,而進程控制塊記錄了進程全部狀態(tài)信息,每一次進程調(diào)度就是一次上下文切換;上下文本質(zhì)就是當(dāng)前運行狀態(tài),主要包括**通用寄存器、浮點寄存器、狀態(tài)寄存器、程序計數(shù)器、用戶棧和內(nèi)核數(shù)據(jù)結(jié)構(gòu)(頁表、進程表、文件表)等。
一次完整的上下文切換通常是進程原先運行于用戶態(tài),之后因為系統(tǒng)調(diào)用或者時間片切換到內(nèi)核態(tài)執(zhí)行內(nèi)核指令,完成上下文切換之后回到用戶態(tài),此時已經(jīng)切換到了另一個進程。
進程狀態(tài)切換
- 運行:占用CPU
- 就緒:由于其它進程運行而暫停運行(通過調(diào)度算法獲得CPU時間,等待下一次調(diào)度)
- 阻塞: 等待某一事件發(fā)生(比如等待輸入/輸出操作完成)而暫停運行。
進程調(diào)度算法
- 先來先服務(wù):非搶占式,不利于短作業(yè)
- 短作業(yè)優(yōu)先:非搶占式,長作業(yè)有可能餓死
- 最短剩余時間優(yōu)先:搶占式。按照剩余運行時間,如果新進程需要的時間更少,則掛起當(dāng)前進程。
- 時間片輪轉(zhuǎn):時間片用完的時候,由計時器發(fā)出時鐘中斷,調(diào)度程序便停止該進程的執(zhí)行,并將它送往就緒隊列末尾,同時CPU時間分配給隊首的進程。時間片太小會導(dǎo)致進程切換頻繁,時間片過長,實時性不能得到保證。
- 優(yōu)先級調(diào)度:為每個進程分配一個優(yōu)先級,為了防止優(yōu)先級低的任務(wù)等待不到調(diào)度,可以隨著時間的推移增加等待進程的優(yōu)先級
合理地設(shè)置各類進程的優(yōu)先級:
參考操作系統(tǒng)——調(diào)度算法
①系統(tǒng)進程優(yōu)先級高于用戶進程;
②前臺進程優(yōu)先級高于后臺進程;
③操作系統(tǒng)更偏好 I/O 型進程(I/O 繁忙型進程)。
- 與 I/O 型進程相對的是計算型進程(CPU繁忙型進程),I/O 設(shè)備和 CPU 可以并行地工作,所以如果讓 I/O 型進程優(yōu)先運行的話,則越有可能讓 I/O 設(shè)備盡早地投入工作,則資源的利用率和系統(tǒng)吞吐量等都會得到提升。
根據(jù)優(yōu)先級是否可以動態(tài)地改變,可以將優(yōu)先級分為靜態(tài)優(yōu)先級和動態(tài)優(yōu)先級兩種。靜態(tài)優(yōu)先級在創(chuàng)建進程時就已經(jīng)確定,之后一直不變;動態(tài)優(yōu)先級創(chuàng)建進程時有一個初始值,之后會根據(jù)情況動態(tài)地調(diào)整優(yōu)先級。
動態(tài)優(yōu)先級的調(diào)整時機:從追求公平、提升資源利用率等角度考慮。如果某進程在就緒隊列中等待了很長時間,可以適當(dāng)提升其優(yōu)先級;如果某進程占用處理機運行了很長時間,可以適當(dāng)降低其優(yōu)先級;如果發(fā)現(xiàn)一個進程頻繁地進行I/O操作,可以適當(dāng)提升其優(yōu)先級。
優(yōu)缺點:優(yōu)點是用優(yōu)先級區(qū)分緊急程度、重要程度,適用于實時操作系統(tǒng),可靈活地調(diào)整對各種作業(yè)或進程的偏好程度;缺點是若源源不斷地有高優(yōu)先級進程到來,則可能導(dǎo)致饑餓。
多級反饋隊列
對于需要連續(xù)執(zhí)行多個時間片的進程,設(shè)置了多個隊列,每個隊列時間片大小不同比如1,2,4,8……??梢钥醋魇菚r間片輪轉(zhuǎn)調(diào)度算法和優(yōu)先級調(diào)度算法結(jié)合。
進程通信
進程是一個獨立的資源分配單元。不同進程(這里通常指的是用戶進程)之間的資源是獨立的,沒有關(guān)聯(lián),不能在一個進程中直接訪問另一個進程的資源。但是,進程不是孤立的,不同的進程需要進行信息的交互和狀態(tài)傳遞,因此需要進程通信。
進程通信的目的包括數(shù)據(jù)傳輸、通知事件、資源共享、進程控制
圖片來源??途W(wǎng)高性能并發(fā)服務(wù)器
圖片來源阿秀的學(xué)習(xí)筆記
管道
無名管道(內(nèi)存文件)
管道是一種半雙工通信方式(只能由一端向另一端發(fā)送數(shù)據(jù)),數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進程中使用。親緣關(guān)系通常是指父子進程關(guān)系,指的是具有公共祖先的進程。
- 管道其實是一個在內(nèi)核內(nèi)存中維護的緩沖器。是一種特殊的文件
- 管道擁有文件的特質(zhì):讀操作、寫操作
- 匿名管道沒有文件實體,有名管道具有文件實體,單數(shù)不存儲數(shù)據(jù)??梢园凑詹僮魑募姆绞綄艿肋M行操作
- 一個管道是一個字節(jié)流,從管道讀取數(shù)據(jù)的進程可以讀取任意大小的數(shù)據(jù)塊,而不管寫入進程寫入管道的數(shù)據(jù)塊 的大小是多少。
-管道的邏輯結(jié)構(gòu)是一個先進先出的隊列,邏輯結(jié)構(gòu)是一個環(huán)形緩沖區(qū)
有名管道(FIFO文件,借助文件系統(tǒng))
也是半雙工通信方式,但是允許在沒有親緣關(guān)系的進程之間使用,先進先出的通信方式。
提供了一個路徑名與管道關(guān)聯(lián),以FIFO的文件形式存在文件系統(tǒng)中,作為一個特殊文件存在,但是FIFO中的內(nèi)容存放在內(nèi)存中。
- 創(chuàng)建有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
一旦使用mkfifo創(chuàng)建了一個FIFO,就可以使用open打開它。命名管道通過命令mkfifo或系統(tǒng)調(diào)用mkfifo來創(chuàng)建
共享內(nèi)存
共享內(nèi)存就是映射一段能被其他進程所訪問的內(nèi)存,這段共享內(nèi)存由一個進程創(chuàng)建,但是多個進程都可以訪問。共享內(nèi)存是IPC里面最快速的方式(不同進程間使用事實上的同一塊區(qū)域,使得進程間使用信息的時候免去“復(fù)制”這一流程,減少開銷。
共享內(nèi)存通常與信號量和管道結(jié)合使用,實現(xiàn)更加復(fù)雜的進程間通信
操作系統(tǒng)提供了一些共享內(nèi)存的系統(tǒng)調(diào)用,例如shmget(獲取共享內(nèi)存區(qū)域)、shmat(映射共享內(nèi)存區(qū)域)、shmdt(解除映射共享內(nèi)存區(qū)域)和shmctl(共享內(nèi)存控制操作)。
共享內(nèi)存存在一些風(fēng)險,因為多個進程都可以訪問同一塊內(nèi)存區(qū)域,所以需要通過互斥機制來確保數(shù)據(jù)同步和安全
使用共享內(nèi)存的時候要注意內(nèi)存大小限制、內(nèi)存清理和維護等
參考阿秀的學(xué)習(xí)筆記
相關(guān)接口
- 創(chuàng)建共享內(nèi)存:int shmget(key_t key, int size, int flag);
成功時返回一個和key相關(guān)的共享內(nèi)存標(biāo)識符,失敗返回-1。
·key:為共享內(nèi)存段命名,多個共享同一片內(nèi)存的進程使用同一個key。
·size:共享內(nèi)存容量。
·flag:權(quán)限標(biāo)志位,和open的mode參數(shù)一樣。- 連接到共享內(nèi)存地址空間:void *shmat(int shmid, void *addr, int flag);
返回值即共享內(nèi)存實際地址。
·shmid:shmget()返回的標(biāo)識。
·addr:決定以什么方式連接地址。
·flag:訪問模式。- 從共享內(nèi)存分離:int shmdt(const void *shmaddr);
調(diào)用成功返回0,失敗返回-1。
shmaddr:是shmat()返回的地址指針。‘
讀端示例
代碼來源于??途W(wǎng)高性能服務(wù)器
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main() {
// 1.獲取一個共享內(nèi)存
int shmid = shmget(100, 0, IPC_CREAT);
printf("shmid : %d\n", shmid);
// 2.和當(dāng)前進程進行關(guān)聯(lián)
void * ptr = shmat(shmid, NULL, 0);
// 3.讀數(shù)據(jù)
printf("%s\n", (char *)ptr);
printf("按任意鍵繼續(xù)\n");
getchar();
// 4.解除關(guān)聯(lián)
shmdt(ptr);
// 5.刪除共享內(nèi)存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
寫端示例
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main() {
// 1.創(chuàng)建一個共享內(nèi)存
int shmid = shmget(100, 4096, IPC_CREAT|0664);
printf("shmid : %d\n", shmid);
// 2.和當(dāng)前進程進行關(guān)聯(lián)
void * ptr = shmat(shmid, NULL, 0);
char * str = "helloworld";
// 3.寫數(shù)據(jù)
memcpy(ptr, str, strlen(str) + 1);
printf("按任意鍵繼續(xù)\n");
getchar();
// 4.解除關(guān)聯(lián)
shmdt(ptr);
// 5.刪除共享內(nèi)存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
消息隊列
消息隊列是消息的連接表,包括POSIX消息對和System V消息隊列。有足夠權(quán)限的進程可以向隊列中添加消息,被賦予讀權(quán)限的進程則可以讀走隊列中的消息;
- 消息隊列是一種被用于進程間通信的有序隊列,將消息以FIFO順序傳遞給接收進程。
操作系統(tǒng)提供了一些消息隊列的系統(tǒng)調(diào)用,例如msgget(創(chuàng)建或打開一個隊列)、msgsnd(向隊列中發(fā)送一個消息)、msgrcv(從隊列中接收一個消息)和msgctl(消息隊列控制操作)等。
-
比起管道,消息隊列有這些優(yōu)點:
1、大量數(shù)據(jù)傳輸。因為消息隊列可以通過多次發(fā)送和接收操作傳輸一個很大的數(shù)據(jù)塊
2、有格式數(shù)據(jù):和管道不同,消息隊列可以傳輸有個事的數(shù)據(jù)。==因為消息隊列傳輸?shù)氖较?,可以根?jù)需要將消息格式化成一定的形式,使數(shù)據(jù)更加靈活方便
3、沒有緩沖區(qū)大小限制,可以傳遞任意大小的數(shù)據(jù)塊,不用擔(dān)心緩沖區(qū)溢出
4、和管道不同,消息隊列可以支持多個進程同時并發(fā)訪問。
5、消息隊列可以存儲未讀信息,這意味著即使接收進程不可用,發(fā)送進程任然可以將消息發(fā)送到隊列中等待接收。
6、消息隊列可以獨立于讀寫進程存在,從而避免了FIFO中同步管道的打開和關(guān)閉可能產(chǎn)生的困難
7、讀進程可以根據(jù)消息類型有選擇的接收消息,而FIFO是默認(rèn)接收的。 -
消息隊列是一種可靠的進程間通信機制,允許接收進程在消息到達(dá)前等待消息到達(dá),并為進程提供了一種可靠的同步機制。
消息隊列為進程提供了以下可靠機制:
- 獨立性:進程可以獨立地執(zhí)行,并且可以將消息發(fā)送給其他進程,而不必考慮接收進程何時接收消息。
- 可擴展性:消息隊列允許多個進程共享一個隊列,并在需要時向隊列中添加或刪除操作。
- 緩沖機制:消息隊列為進程提供了一種可靠的緩沖機制,可以在繁忙的進程間傳遞消息,從而避免了消息丟失的可能性。
- 可靠性:消息隊列提供了一種可靠的進程間通信機制,允許接收進程在消息到達(dá)前等待消息的到達(dá)。
信號
用于通知進程某個事件已經(jīng)發(fā)生。按crtl+c就是一種信號
除了用于進程間通信之外,進程還可以發(fā)送信號給進程本身:
- 強制進程重置自身狀態(tài),發(fā)送SIGTERM信號終止當(dāng)前操作并重置自身狀態(tài)
強制進程退出:SIGKILL強制終止自身
程序執(zhí)行控制:進程可以使用SIGUSR1和SIGUSR2等自定義信號來實現(xiàn)自身的程序控制執(zhí)行
信號量
信號量是一個計數(shù)器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,實現(xiàn)進程、線程對臨界區(qū)的同步以及互斥訪問。多進程使用的是SYSTEM V信號量。
信號量主要作為進程間或者同一進程不同線程的同步手段
內(nèi)存映射
操作系統(tǒng)將一個文件映射到進程的地址空間中,以便直接訪問文件內(nèi)容。內(nèi)存映射將文件的一部分或者全部內(nèi)容映射到進程的地址空間的一段虛擬內(nèi)存中,進程可以像訪問普通內(nèi)存一樣訪問這些數(shù)據(jù)。
內(nèi)存映射是一種虛擬內(nèi)存管理技術(shù),它可以將磁盤文件映射到進程的地址空間中。
內(nèi)存映射提高了IO操作的效率,因為讀取和寫入文件的內(nèi)容可以像訪問內(nèi)存一樣快速完成,此外,還可以提高進程之間的通信效率,因為多個進程可以訪問映射同一文件的不同部分。
內(nèi)存映射還提供了一種更加靈活的IO操作方式,例如將文件映射到不同進程或者不同地址空間中。
內(nèi)存映射和共享內(nèi)存的關(guān)系?區(qū)別是什么?
首先,內(nèi)存映射和共享內(nèi)存都是用于進程之間通信和共享數(shù)據(jù)的機制。它們主要作用是提高進程間通信的效率和簡化程序?qū)崿F(xiàn)。
- 區(qū)別:
1、對象:內(nèi)存映射將一個文件映射到進程地址空間;共享內(nèi)存是將一塊內(nèi)存在多個進程之間共享;
2、訪問方式:mmap通過虛擬內(nèi)存機制實現(xiàn)磁盤數(shù)據(jù)直接映射到進程內(nèi)存中,支持隨機訪問;共享內(nèi)存需要使用系統(tǒng)顯式操作內(nèi)存,支持隨機訪問
3、同步方式:mmap通常需要使用信號量等同步機制確保進程訪問文件的正確性;共享內(nèi)存可以通過鎖等機制來確保多個進程對共享數(shù)據(jù)的順序訪問。 - 相似
1、都是用于進程通信和共享數(shù)據(jù)
2、都支持高效率數(shù)據(jù)共享,可以顯著提高程序執(zhí)行效率
3、都存在同步機制,確保數(shù)據(jù)完整性和安全性
socket
可以用于不同機器之間的通信(網(wǎng)絡(luò)通信)
輔助命令
ipcs命令用于報告共享內(nèi)存、信號量和消息隊列信息。
- ipcs -a:列出共享內(nèi)存、信號量和消息隊列信息。
- ipcs -l:列出系統(tǒng)限額。
- ipcs -u:列出當(dāng)前使用情況。
線程通信
圖片來源阿秀的學(xué)習(xí)筆記
Linux
信號
類似于進程間的信號處理
鎖機制
1、互斥鎖
2、自旋鎖
3、讀寫鎖
讀寫鎖是一種在多線程編程中的同步機制,用于控制同一時刻由多少個讀操作和寫操作。
讀寫鎖由兩種鎖定狀態(tài):讀鎖和寫鎖。讀鎖狀態(tài)下,多個線程可以同時讀取共享資源,但是只有一個線程可以獲取寫鎖來修改這個資源。寫鎖狀態(tài)下,只有一個線程可以修改共享資源,其它線程無論讀或者寫都會被阻塞,直到寫鎖被釋放。讀寫鎖的目的是使多個線程能夠同時讀取共享資源,提高并發(fā)性能。
讀寫鎖有兩種實現(xiàn)方式,讀優(yōu)先和寫優(yōu)先。讀優(yōu)先使可以使得多個線程獲得讀鎖,但是當(dāng)一個線程有寫鎖的時候,其它線程都被阻塞;寫優(yōu)先是優(yōu)先處理寫操作,寫操作處理完之后才處理讀操作。
- C++實現(xiàn)讀寫鎖
C++讀寫鎖
讀寫鎖通常被用于對于讀操作頻繁但是寫操作較少的共享資源,例如數(shù)據(jù)庫查詢??梢蕴岣卟l(fā)性能,減小鎖的爭用,降低線程之間的競爭。
條件變量
使用通知的方式解鎖,與互斥配合使用文章來源:http://www.zghlxwxcb.cn/news/detail-427589.html
信號量
包括無名線程信號量和命名線程信號量。多線程同步的信號量是POSIX信號量。文章來源地址http://www.zghlxwxcb.cn/news/detail-427589.html
Windows
- 全局變量:需要有多個線程來訪問一個全局變量時,通常我們會在這個全局變量前加上volatile聲明,以防編譯器對此變量進行優(yōu)化
- Message消息機制:常用的Message通信的接口主要有兩個:PostMessage和PostThreadMessage,PostMessage為線程向主窗口發(fā)送消息。而PostThreadMessage是任意兩個線程之間的通信接口。
- Message消息機制:常用的Message通信的接口主要有兩個:PostMessage和PostThreadMessage,PostMessage為線程向主窗口發(fā)送消息。而PostThreadMessage是任意兩個線程之間的通信接口。
到了這里,關(guān)于操作系統(tǒng)進程線程(一)—進程線程協(xié)程區(qū)別、多進程多線程、進程調(diào)度算法、進程線程通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!