不謀萬世者,不?謀?時。不謀全局者 ,足謀?域 。
????????????????????????????????????????????????????????????????????????——陳澹然《寤?》《遷都建藩議》
操作系統
一.對文件簡單操作的常用基礎指令
?ls
ls 選項 目錄或?件名:羅列當前?錄下的?件
-l:以長格式顯示?件和?錄的詳細信息
-a 或 --all:顯示所有?件和?錄,包括以.開頭的隱藏?件和?錄
ls -l=ll
?件路徑
絕對路徑 相對路徑
pwd:查看程序員當前所處的?件路徑
ls /root 選項:對路徑root下的?件進?相關操作
./:當前?錄
../:上級?錄
cd
cd ?件路徑:進?指定?件路徑
cd -:躍遷?跳轉前的路徑
cd ~:返回當前?戶的家?錄
touch
touch ?件名:創建?個新的?件
mkdir
mkdir ?錄名:在當前?錄下創建?個新?錄
mkdir -p ?串路徑:在當前?錄下創建?串新路徑
*通配符:表示指定路徑下擁有指定特性的所有文件
man
man 指令:查看指定指令詳細信息
nano
nano test.c:創建記事本“test.c”并打開
cp
cp test1.c test2.c:將?件test1的內容拷?到test2中去
cp -r lesson2 tar:將?錄lesson2及其所有?件遞歸式拷?到tar中
mv
mv dir mydir:將?件dir重命名為mydir
mv dir /path:將?件dir移動到路徑path中
cat/tac
cat test.c:打印?件test內容
cat -n test.c:打印時顯示?號
cat -s test.c:不打印多?空?
cat -b test.c:空?不計??號計算
tac test.c:將?件test以?為單位?下?上打印
echo
echo "hello" test.c:將字符串"hello"寫??件test
重定向操作符
>:輸出重定向操作符
> new.txt:新建?個?件“new.txt”
echo "a" > new.txt: 覆蓋添加到?件中
echo "a" > new.txt:將字符"a"同時寫?新創建的?件new.txt
>>:追加重定向操作符
echo “a” >> test.txt:對已有?件的內容進?擴充 append
|:流水線管道指令
find ?件名:查找此?件所在路徑
which 指令:查找此指令所在?件路徑
grep 字符串 ?件:將指定?件中所有含有指定字符串的字段打印
grep -i 字符串 ?件:不分??寫
grep -n 字符串 ?件:打印此字段所在?
zip:壓縮
zip 233.zip 233
zip -r dir.zip dir:解壓?錄
unzip:解壓
unzip 233.zip unzip 233.zip -d mydir:將?件233解壓到mydir
nano ?件名:新建?個記事本
uname -a:查看當前機器更詳細的信息
shut down:關機
二.權限
1.有關權限的常用指令
su ?戶名:成為預期?戶
sudo touch ?件名:新建?個超級?戶權限?件
2.文件權限屬性簡單概要
r:讀 ????????w:寫 ????????x:執? ????????d:?錄 ????????-:普通文本文件
3.文件訪問權限
這么做的目的是為了精細管理
4.使用chmod進行權限更改
chmod u/g/o +/- rwx
eg:chmod u-w lesson1:給?件lesson1對擁有者解除指定權限
u:擁有者
g:所屬組
o:other
+/-:添加或去除權限?
chmod u-rwx,g-rwx,o-rwx file 去除所有權限
二進制更改權限法
chmod 664 lesson1:就是更改為;110:100:100,
?錄的權限
新建?個?錄,默認權?是775(111 111 101)
新建?個普通?件,默認權限是664(110 110 100)
5.chown
更改?件擁有者
chown AOKANA other.zip:將?件other.zip擁有者更改為AOAKNA
6.權限掩碼umask概要
定義:umask是?個三位?進制數,?于定義在創建?件和?錄時默認應該屏蔽掉的權限位。
功能:通過umask設置,系統能夠確定新創建的?件和?錄的默認權限 umask只能禁?權限,不能啟?特殊權權限,如需修改權?需使?chmod命令。umask存在的意義是為了解決?件默認權限Linux系統中,?件的最?默認權限是666(即rw-rw-rw-),表示所有?戶擁有讀寫權限,但沒有執行權權限。 查看umask:umask (ps: 只關?最后三個數字) 修改umask:umask 000~777
7.umask相關計算
為什么我們新建?個?錄
默認權?是775( 111 111 101) 新建?個普通?件, 默認權限是664( 110 110 100)
三.VIM
1.vim常用操作簡述
vim模式及其切換簡介
vim界?左下?可以看?當前vim所處模式
光標所在?相關命令
1. 復制:yy
2.粘貼:p
3.撤銷:u
4.ctrl+r:撤銷u
5.剪貼:dd p
6.刪除:dd 數字+dd:連續刪除??
光標快速定位相關命令
shift+g(G):將光標直接定位到?件結尾
gg:將光標快速定位到?本開頭
n+shift+g(n+G):將光標定位到指定?
shift+4=$:將光標移動??尾
shif+6=^:將光標移動???
w:單詞為單位,向后跳轉 單詞:以空格為分隔的字符串
b:單詞為單位,向前跳轉
x:光標所在位置向右→逐個字符進?刪除
shift+x:光標所在位置向左←進行逐個字符刪除
shift+~:??寫切換
shift+r替換模式:將當前字符替換
?
2.如何查看vim?持的模式
底?模式 :help vim-modes
ctrl+b:向后移動??
ctrl+f:向前移動??
ctrl+u:向后移動半?
ctrl+d:向前移動半?
3.如何對vim文件使用gcc進行編譯
gcc -o code code.c:對?件進?編譯
./code:運?此?件
底?模式輸? :set number 使代碼前顯示?號
4.調試前的準備?作
在對?個代碼?件進?調試前,需要?-g對其添加調試信息
如果我有?個test.c?件,我要對其進?調試,那我需要使?指令:gcc -g -o test test.c
(ps:使?此執??成新的可調式的可執??件之前需要先清除舊的可執??件)
5.有關打斷點的操作
gdb+某編譯過后的?件名:對此?件進?debug模式
quit:退出出debug模式
l+代碼?號:看到指定?號及其附近的代碼
b+?號:在對應的?號打上斷點
info b:查看當前所有斷點信息
d+斷點編號:刪除指定編號的斷點
disable+斷點編號:禁?此段點
enable+斷點編號:啟?此段點
r:運?當前程序
bt:顯示當前線程的調?棧
n:單步執?,不進?函數內部
s:單步執?,進?函數內部
p+(&)變量:打印?個變量的值(or地址)
until+?號:讓代碼運?到指定的?
cgdb
watch+變量:監視指定變量的值發?的變化
condition+斷點編號+變量名==數值:添加條件斷點
四.makefile簡介
make是指令 Makefile是?件 相當于cmake
將此段代碼寫?到vim?件Makefile中再使?make可以將此?件直接進??動編譯 Makefile的本質就是依賴關系和依賴?法的結合
?般這么寫?個.exe?件
?
.PHONY是?來聲明?標的,clean是?個偽?標,并不是?個真正的?件名
五.進程概述
1.計算機進程概念簡述
在計算機中,進程(Process)是操作系統中資源分配和調度的基本單位,簡單來說,它就是一個正在運行的程序。
更通俗地講:
-
一個程序(如 Word、瀏覽器)本身是靜態的文件;
-
當你運行這個程序時,操作系統會為它分配資源(如內存、CPU時間等),并將它變成一個活動的執行單元,這就是進程。
2.進程概念圖示
3.什么是PCB
進程:PCB,進程控制塊(任務結構體) PCB就是內核數據結構
PCB(Process Control Block,進程控制塊)是?個?來描述和控制進程運?的數據結構,它是進程
實體的?部分,也是操作系統中最重要的記錄型數據結構
PCB是?個包含了進程所有關?信息和狀態的數據結構,?于操作系統的進程管理。
進程=程序的代碼和數據+內核數據結構(PCB:task_struct)
進程不僅僅是將相關?件從磁盤加載到內存中
task_struct就是程序運?時其所描述此段程序相關的所有信息,然后操作系統會將所有的task_struct使
?相關的數據結構?接起來
最終轉換為對?個list的"增刪查改"
為什么要有PCB:OS要以先描述,再組織的?式進?管理
4.Linux下如何查看進程相關參數
將程序運?起來,本質就是在系統中啟動了?個進程
進程分兩種:
1.執?完就退出
2.?旦運?,程序員不主動關?其將不會結束(常駐進程)
有關進程監視的?些指令
ps -e:顯示所有進程
ps -ajx:顯示所有?戶終端控制進程,可?于查看PID,PPID
ps -ajx | head -1:提取?條進程快照
ps ajx l grep process 常?的查進程的指令
kill 9+pid:結束?個進程
ls /proc/28824:只要我們啟動?個進程,此進程便會以其pid作為?件名放?到?錄proc中以便管理員查
看(ps:這里的28824是?個pid)
proc并不存在磁盤上,它是由內存動態?成的數據
5.如何查看pid
查看子進程
查看父進程pid
6.fork?進程?進程的機制
Linux下,新創建的任何進程都是由?進程創建的
如何在vim中查看ppid
bash:命令?解解釋器
六.使?系統調?創建進程
1.有關fork()函數簡單介紹
fork 函數的返回值?于區分調?進程(?進程)和新創建的進程(?進程)。具體來說:
當 fork 在?進程中被調?時,它會返回新創建的?進程的進程ID(PID),這個值是?個正整數,?于零。
當 fork 在?進程中被調?時(實際上,?進程是從fork調?點開始執?的副本),它會返回0。
如果 fork 調?失敗,它會返回-1,并設置errno來指示錯誤原因。
?進程會繼承?進程的內核數據結構 還有代碼段 數據段 堆棧段 包括變量fd等
??進程不同點有 進程ID(PID) 內存空間 ?件偏移量 執?路徑 系統資源
fork->兩個進程->此?進程為??關系->此?進程代碼共享,但數據相互獨?
2.進程的幾個重要特性
繼承性:?進程在創建時會繼承?進程的環境和資源,但并?所有資源都會被繼承。例如,
?進程會繼承?進程的代碼段和數據段,但常會獲得??的獨?堆棧空間
獨?性:?旦創建,?進程便獨?于?進程運?。這意味著?進程的終?不會影響?進程的
運?(除?有特別的設置,如某些操作系統中?進程可以發送信號給?進程要求其終?)
反之亦然。
所以說?論啥進程,它們運?之間是相互獨?的 所以其代碼權限為只讀 數據各?私有?份
七.操作系統進程狀態
1.并?和并發
并發:多個進程在單個 CPU下?進程切換的?式,在?段時?內,讓多個進程得以輪流運?
并?:多CPU的服務器可以同時運?多個進程(或CPU和其他硬件同時運?)
a.cpu執?代碼,是給每?個進程預分?個時間?,基于時間?進?調度輪轉
2.時間?
??級別OS是分時OS,(?的是為了任務公平)
對應的還有實時操作系統,
3.進程具有獨?性
4.等待的本質(power point):???標外部設備,CPU不調度
運?:只要PCB在隊列中,該進程便被叫做運?狀態
就緒和運??般情況下是合?為?的
掛起:阻塞期間,如果OS內存不?,OS便會將特定等待外設的PCB換出到磁盤當中,磁盤中有專
門的swap分區?持此操作
被換出的PCB是處于阻塞掛起的狀態
2.進程運行示意圖
3.如何查詢一個進程狀態
ps aux:?于實時顯示系統中各個進程的資源占?狀況,包括CPU使?率、內存占?情況等
按鍵操作:在top界?下,?戶可以通過按?進?交互操作。例如,按P鍵可以按照CPU使
?率進?排序,按M可以按照內存使?率進?排序。
退出:按下q?可以退出top命令。
3.進程優先級
ps -la:最終優先級的設置=PRI(default 80)+NI(NICE)
nice∈[-20,19]
所以說調整進程優先級可同過調整nice值進?控制
?件權?管理的實現原則就是通過進程的UID(?戶標識符)和?件的擁有者所屬組ID進?對?從?實現權限控制
?件可追溯是誰的,進程可追溯知道是誰的,?這進?對?,進?進??件的權限管理
4.進程切換概述
5.進程切換流程的兩個核?步驟:進程上下?數據的保存和恢復和CPU ?作順序
6.Linux下進程調度基本算法圖示
active和expried的協作
每個PCB?開始在active中,時間??到便會進?expried中
active隊列永遠是?個存量進程競爭的情況(PCB減少)
時間??到 active的進程進?expried對列
到達?定程度后,active指針和expired指向會互相交換指向內容,如此循環
八.命令行參數argc與argv
1.命令行參數簡介
argv[0]常代表程序的名稱
當你從命令?運??個程序時,
操作系統會將程序的名稱作為第?個參數傳給該程序,
這個名稱是?個字符串,
它包含了程序的路徑(如果是從某個?錄運?的話)和程序的?件名
argv[0]:程序的名稱(可能包含路徑)。
argv[1]:傳給程序的第?個命令?參數。
argv[2]:傳給程序的第?個命令?參數。
...
argv[argc-1]:傳給程序的最后?個命令?參數。
argv[argc]:這是?個NULL指針,?于標記數組的結束。
它不是?個有效的參數,?是?作哨兵值,
以確保函數可以安全地遍歷數組?不會越界。
2.命令行流程
main參數是誰傳遞的
所以指令不僅僅是指令,也是進程
user在命令?輸?的是字符串,此字符串?先被shell(命令?解釋器)拿到,shell將這些字符串按照空格打散,放??張表(argv)并計算出?個參數argc
3.環境變量
環境變量是OS中的?些基本信息,具有全局屬性
作?于存儲配置信息
為系統的程序運?提供必要?持和保障
PATH:定義可執??件查找路徑
HOME:?戶登錄時,當前所在?錄會設置成他們的家?錄
SHELL:
PWD:保存當前進程所在的?作路徑
LANG 和 LC_* 系列:控制程序的語?和地區設置。
TMPDIR:指定存放臨時?件的?錄。
4.環境變量與本地變量
本地變量(也稱為局部變量)?般是由?戶(即程序員)在編寫程序時?定義的。
這些變量在函數或代碼塊的內部被聲明,?于存儲臨時數據或作為函數執?過程中的中?結果。
5.殺進程
kill -9 1234 殺進程
向進程ID為1234的進程發?SIGKILL信號,強制終?它。
常?信號(os發信號來殺進程)
SIGTERM (15) 請求終?進程,可以被捕獲和處理。默認信號。
SIGKILL (9) 強制終?進程,不能被捕獲,阻塞或忽略。
SIGHUP (1) 常?于讓進程新讀取配置?件。
SIGINT (2) 中斷進程(常由Ctrl+C產?)。
SIGSTOP (19) 停?進程的執?,但保持其狀態不變。
SIGCONT (18) 繼續執?已經停?的進程。
6.進程的終止
exit(狀態碼) 退出狀態碼:?于判定代碼跑完,結果對不對
return 0中的0是退出碼
exit(0) 表示程序成功執?并正常退出。
?零的退出狀態碼 exit(失敗狀態碼)
進程退出由退出碼和退出信號值進?整體評估
ps:?進程只有程序執?失敗才會執?exit
7.waitpid
等待的?的是為了房?僵?進程且獲取?進程退出信息(為了讓?戶??決定某些東?)
允許?進程等待?進程結束,
如果id為-1,則waitpid將等待任何?個?進程結束。
如果id為0(?進程),則等待與調?進程屬于同?個進程組的任何?進程。
如果id?于0(?進程),則等待具有該PID的?進程。
NULL:這是waitpid函數的第?個參數,?于存儲?進程的結束狀態
返回值:成功則返回?進程號 0代表?已退出?進程等待(WNOHANG)
8.圖示父進程和子進程間運作關系
9.寫時拷貝簡介
數據需要被寫?才進?拷?操作 此前 對個對象或內存共享同?內存數據
10.進程程序替換
進程替換:進程數據結構不變 但是代碼數據替換
調?接口execl后,此接?會?指定代碼和數據替換調?此接?的代碼和數據
新程序的代碼和數據覆蓋?程序的代碼和數據
execl("帶路徑的?進制可執?程序","命令","選項",...);
成功時execl?返回值,失敗了,覆蓋失敗返回-1
execl本質是將程序加載到內存
九.?件操作
1.將?化內容打印到顯示器
printf()
fputs("a",stdout):將字符(串)"a"輸?到指針(流)所指向的?件(屏幕)中
fwrite("a",1,4,stdout):將字符串"a"寫?到標準輸出流stdout中去
fprintf(stdout,"a")
2.flag
int open(char *pathname,int flag)
flag ?件打開標志 本質是宏
O_RDONLY:只讀
O_WRONLY:只寫
O_RDWR:讀取+寫?
O_CREAT:創建?件
O_APPEND:向?件末尾追加(append)內容
注意:O_APPEND標志?常與O_WRONLY或O_RDWR一起使?。
int open(const char*pathname,int flags,mode_t mode);
mode_t mode:賦予此?件的"起始權限"
如果希望mode是最終權限,可以 umask(0)
進程的umask默認來?系統,如果在進程中設置了,那么就近原則
write(fd1, message, strlen(message));
將字符串message存儲的數據寫?到fd1所打開的?件
寫???由strlen(message) 字符串實???所決定
3.fd簡介
文件描述符是一種整數,用于標識一個打開的文件或 I/O 資源。
在 Unix/Linux 系統中,幾乎一切皆文件,不僅是普通文件,包括目錄、套接字、管道、終端、網絡連接等都可以用 fd 表示。
每當你打開一個文件,操作系統會:
-
把這個文件信息記錄到內核的一個文件表里;
-
返回一個整數給你,這個整數就是文件描述符(fd)。
你之后對文件的操作(讀、寫、關閉等),都是通過這個 fd 來進行的。
4.read write和fd如何形成聯動進行文件數據的訪問
、
fd:?個整數 File Descriptor 可看作是?件的下標
stdin(標準輸?):?件描述符為0,常?于接收?戶輸?。
stdout(標準輸出):?件描述符為1,常?于程序的正常輸出。
stderr(標準?誤):?件描述符為2,常?于程序的錯誤輸出。
ssize_t read(int fd, void *buf, size_t count);
fd:?件描述符,唯?標識?個打開的?件。
buf:?戶空?緩沖區指針,?于存儲讀取的數據。
count:希望讀取的字節數。
返回值:實?讀取的字節數,如果讀取失敗則返回-1
ssize_t write(int fd, const void *buf, size_t count);
fd:?件描述符,唯?標識?個打開的?件。
buf:?戶空?緩沖區指針,指向要寫?的數據。
count:希望寫?的字節數。
返回值:實際寫?的字節數,如果寫?失敗則返回-1
4.進程對文件系統進行訪問簡圖
fd?件標識符是?個數組下標 fd是?件描述符表的索引 ?的是為了使進程快速定位到對應的?件表項
其?的是為了讓?件和進程?產?關聯 ?件表項包含了關于打開?件的信息 如狀態標志(只讀只寫) 當前offset等
這是進程訪問?件的唯??式
c語??件訪?相關函數FILE就是對fd的封裝 這樣可以?免user去記憶?件fd的麻煩
stdin stdout stderr就是cpp函數對?件類型的封裝 成為struckt_file類型 任何語?要對fd=0 1 2進?封裝
封裝???是為了?便 另???是為了可移植性(跨平臺性)
4.外存設備的文件管理系統概述
對于任何?個?件
其內容本身就是?個巨?的?維數組
標識?件任何?個區域
使?偏移量(offset)+??的?式
偏移量(Offset)指的是從某個點開始
到某個位置?距離
偏移量主要作?于定位數據
偏移量就是?件開頭到當前讀寫位置的字節數
5.LBA的計算公式
LBA的計算公式 LBA的計算公式為:LBA = NH × NS × C + NS × H + S - 1
其中: NH為磁頭數(Heads Per Cylinder,HPC),即每個柱?的磁頭數或磁?數。 NS為每磁?扇區數(Sectors Per Track,SPT),即每個塊的扇區數。
C、H、S分別為柱?、磁頭和扇區的編號 LBA=塊號*8+[1,8]
6.磁盤對文件的分組管理圖示
7.Block group簡介
和啟動有關
超級塊(Super Block):就是?件系統 ?于表示整個分區的整體情況 影響整個分區 是?個分區?臟
Super Block掛掉后系統會?其他分區的Super Block來恢復它
存儲?件系統本身的元數據,如塊和inode的總數、未使?的塊和inode的數?、塊和inode的?? 等
是?件系統的核?結構之?,如果超級塊被破壞,整個?件系統結構可能會受到影響。
塊組描述符(Group Descriptor Table, GDT):對以下四個信息進?管理
描述塊組的屬性信息,如塊位圖、inode位圖、inode表和數據塊的位置等。
在具備Flexible Block Groups特性的?件系統中,塊組描述符?于描述管理數據(如位圖)的位置。
塊位圖(Block Bitmap):刪除數據就是將BB和IB中?件對應編號和數據塊所占位圖據?特位由1變0
記錄數據塊的使?情況,即哪些數據塊已經被占?,哪些數據塊還未被使?。
占??個邏輯塊的存儲空間(常為4KB),其中每?位表示?個數據塊的狀態。
inode位圖(Inode Bitmap):和inode table中的imode形成映射,對inode進?管理 Block Bitmap同理
記錄inode表的使?情況,即哪些inode已經被分組,哪些inode還空?可?。
與塊位圖類似,也占??個邏輯塊的存儲空間。
inode表(Inode Table):inode以分區整體為單位進?分組 分組時只要確定起始inode即可
每組inode固定 inode保存在GDT中 ?件加載到內存中本質是將其inode加載到內存中
以列表形式保存?件的元數據,包括?件的inode號、??、擴展屬性和訪?時?等。
inode表的??根據?件系統的屬性和格式化時的設置?定。
數據塊(Data Blocks):
存儲?件數據的區域,是?件內容的實際存放位置。
數據塊的數?和??取決于?件系統的設計和配置。
8.有關Inode Table和Data Block的映射
9.磁盤對文件的操作
如何查找?個?件
先根據inode確定在哪個group(GDT)中
再?inode-start_node=inode bitmap
由此再確定inode table,然后也找到了data block
最終查找到想要的?件
OS查找?件夾是對絕對path?左向右遍歷進?的
如何刪除?個?件
找到后將bitmap由1->0,將block bitmap由1->0
如何修改
找到后對inode table,或者data block進?修改
如何新增
先將inode_bitmap和block_bitmap由0->1
申請完塊后將屬性填?,再對GDT進?更新
再返回?個inode給?戶
10.有關目錄dentry概述
?錄的數據塊存儲?件名(inode的映射關系),根據?件名和inode的映射關系從?對其他?件進?查找,
之后屬性內容便全有了
?錄的data block中存儲的其??件的inode path
rwx如果沒有r,就是系統不讓你去讀取此?件的data block,你也就?法獲取inode和?件名的映射關系
Linux中不需要存儲路徑,他只要再Data Block中存儲的?件名與inode的映射關系
路徑解析:
dentry?于存儲?件名和相關的??錄指針,幫助內核在?件系統的?錄樹中解析路徑
OS對?件path緩存:每?個?件都有dentry 這樣對?件的管理就可以轉換為對dentry cache的管理
dentry緩存了?錄項的信息,減少了復查找?錄項所需的磁盤訪問次數
緩存的dentry對象存儲在dentry cache(也稱為dcache)中,這是?個全局的哈希表,允許快速查找。
dentry 內存級別內核數據結構 在OS中是?個dentry tree?于path的cache
快速查找:?錄的data block中存放的?件名 inode和?件名可以形成映射關系
當?個路徑被解析時,內核會?先嘗試在dentry cache中查找相應的dentry對象。如果找到,內核可以直接使?它
??需再次訪?磁盤。
如果dentry緩存中不存在所需的條?,內核會進?磁盤訪?來查找,并將找到的條?添加到dentry cache中。
?錄項管理:
dentry對象與?件系統上的實際?錄項相對應,并且包含指向inode的指針
通過dentry和inode的結合,內核可以?效地管理?件和?錄。
命名和刪除:
dentry結構還?于處理?件?命名和刪除操作。這些操作會相應地更新dentry緩存和?件系統上的?錄項。
符號接解析:
當解析?個符號?接時,dentry結構會?于存儲符號?接的?標路徑,并幫助內核進?進?步的路徑解析。
task_struct->FILE->path->denty->inode->外存
如何確認你在哪個分區下
訪問任何?件都需要路徑, ?這個路徑的前綴就是分區
11.軟硬鏈接
如何理解軟硬?接
a.軟鏈接是獨?的?件 有獨?的inode 內容上 保存的是?標(其指向)?件的路徑 類似于Windows的桌?快捷?式
b.硬鏈接本質上是inode和數據塊中?件名的映射關系
硬鏈接不是獨??件?獨?的inode 其本質就是?組?件名和?組已經存在的?件
是同?個?件的兩個不同名字。刪除其中?個?件不會影響到另?個?件或?件的內容。
硬?接數(引?計數)
11.軟硬鏈接存在意義
a.軟鏈接
如何創建?個軟鏈接 ln -s [?標?件或?錄] [軟鏈接名稱]
如何刪除?個軟鏈接 unlink/rm 軟鏈接名
b.硬鏈接
如何創建?個硬鏈接
硬鏈接數=當前?件(./ 1個點)+此路徑下?個?件(../ 2個點)+此路徑下?個?件的下?個(.../)...
硬鏈接的存在很好的解決了?件備份的題 但是Linux不允許對?錄建?硬鏈接其?的是為了防止環狀路徑
軟鏈接可以是因為系統對軟鏈接不做處理
軟鏈接可以看作是?個簡化的?件路徑
將user想要快速訪問到的?件的路徑變成?個?件放在易于接觸到的區域
就?如桌?
硬?接就是?標?件的倒影
對硬?接的數據塊會inode進?改動其?標?件對應數據也會發?改動
十.動態庫和靜態庫:庫就是.o?件的打包
1.如何使?動態鏈接庫
a.編寫源代碼
b.編譯成?標?件
使?-c選項編譯原?件 但不進??接
gcc -c -fPIC mylib.c -o mylib.o
-fPIC選項?成與位置?關的代碼
Position Independent Code
這是創建共享庫所必需的。
共享庫(Shared Library)是?種特殊的程序庫,
它在操作系統的內存中只被加載?次,
但可以被系統中的多個程序同時使?o
c.創建共享庫
使?-shared選項?成共享庫?件
gcc -shared -o libmylib.so mylib.o
2.如何使?靜態鏈接庫
a 編寫源代碼 mylib.c
b 編譯成?標?件 使?-c選項編譯源?件
gcc -c mylib.c -o mylib.o
c 創建靜態庫 使?ar?具?成靜態庫?件
ar rcs libmylib.a mylib.o
3.動靜態鏈接庫在運行時的差別
動態鏈接庫:在運?時加載,
需要設置運?時庫搜索路徑(如LD_LIBRARY_PATH)
靜態鏈接庫:在編譯時嵌?到可執??件中,
運?時不需要額外的庫?件
4.elf形成原理概括
size ?進制?件:?于查看?進制?件??信息
靜態庫在編譯時被?接到程序中(和其他程序?接打包成ELF) ?動態庫則在程序運?時被加載到內存中。
5.elf組成概括
elf格式圖
6.elf和靜態庫archive在內存中的加載
elf還未加載到內存時,已經按照[000,FFF]進?編址了
這就是虛擬地址
所以虛擬地址不僅是OS在內存中形成進程時才會?成
在編譯器編譯時就形成了
平坦模式下,邏輯地址=起始地址(為0)+虛擬地址 ps:主流OS皆為平坦模式(offset=0)
邏輯地址(磁盤 ELF) == 虛擬地址(加載到內存中)
程序內存依靠虛擬地址來跳轉函數
mm_struct的<未初始化數據><初始化數據><正?代碼>區域的數據是
加載elf的各個section的各個具體adress得來的
7.有關頁表的圖示介紹
mm_struct是什么
加載?個ELF?件只需要將它的??地址加載?內存即可
如果CPU在尋址時虛擬地址匹配失敗未轉化為物理地址
進?懶加載section即可
(pc:當前正在執?的指令虛擬地址的寄存器)
在編址時,ELF的頭部就已經記錄了Enter point address
(整個程序的??地址,放?pc即可)「_start」
CR3:保存?表起始物理地址的寄存器 ?于切換進程
EIP:將pc中的地址通過MMU轉化為物理地址
8.動態庫的加載的理解
動態庫加載到內存需要OS管理
因為OS中可能同時存在多個庫
管理?式依舊是「先描述?后組織」
十一.通信
1.進程間通信IPC?的和?段
進程間通信存在?的:
數據傳輸 資源共享 通知事件 進程控制
進程間通信前提是讓不同進程看到同?份資源
同?份資源
某種形式的內存空間
提供資源者有且僅有OS
2.進程間通信分類
管道
?anonymous pipes
?命名管道
System V(std) IPC
?system V 消息隊列
?system V 共享內存
3.pipe簡單圖示意
4.本地間通信
a.進程間通信IPC?的和?段
進程間通信存在?的:
數據傳輸 資源共享 通知事件 進程控制
進程間通信前提是讓不同進程看到同?份資源
同?份資源
某種形式的內存空?
提供資源者有且僅有OS
b.anonymous pipe?作原理概述
特性
若pipe為空且正常 讀取數據會阻塞
管道為滿且管道正常 表示會阻塞
pipe寫端關閉且讀端繼續 讀端讀到0 表示讀到?件結尾
管道寫端正常 讀端關閉 OS會直接殺掉寫?進程 (OS會給寫端的進程發信號 13)SIGPIPE)
5.進程間通信system V共享內存
6.共享內存的創建與使?
共享內存獲取函數shmget的使?
?
shmget(key_t key,size_t size,int shmflg);
size:user期望?成的shm??
shmflg:
IPC_CREAT:單獨使?此選項,如果shm不存在,創建,如果存在,則獲取它并返回————保證進程可以拿到共享內存————獲取共
享內存選項
IPC_EXCL:存在就出錯
IPC_CREAT|IPC_EXCL:若shm不存在,那么就創建它,如果存在,則出錯并返回————只要成功就?定是新的shm(不使?舊shm)
————創建共享內存選項
IPC_EXCL 單獨使??意義 ?者需要組合使?
key:user輸?
如何保證shm唯?性:讓shm的標識符key不同即可
如何保證不同的進程看到的是同?個共享內存:這個key為何不讓OS??形成?
如果由操作系統形成,那么將由?個進程形成另?個進程則?法獲取到此key
返回值:shmflg成功后會返回獲取的shm標識符(int)(成功返回值和fd(?件下標,shm本質上是?件)?樣)
shmat:讓進程虛擬地址和shm標識符形成關聯
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:需要掛接的user創建的共享內存(下標) shmget成功返回值
shmaddr:由user指定,掛接到指定虛擬地址上(暫時不需要,程序應?
層不強調虛擬地址空指針這?概念,故shmaddr=nullptr即可)
shmflg:設置為0即可
返回值:因為是掛接到地址上,所以返回值類型是共享內存地址(指針)
若成功:返回掛接的共享內存段的起始地址,?便user后續對共享內
存進?操作
若失敗:返回-1
shmdt:讓shm下標和進程虛擬地址去關聯
int shmdt(const void *shmaddr);
shmaddr:shmat的返回值
和哪?個地址去關聯,所以傳?地址
返回值:成功返回0,失敗返回-1
shmctl:控制共享內存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:shm的下標
cmd:控制命令,?于指定要執?的操作
常?的命令包括IPC_RMID(刪除共享內存段)和IPC_SET(修改共享內存段的屬性)
IPC_STAT(?于獲取IPC對象狀態)
buf:指向struct shmid_ds結構的指針,?于存儲或獲取共享內存段的信息
可以為NULL,表示不獲取或設置共享內存段的信息。
返回值:成功返回0,失敗返回-1
msgsnd,msgqid消息信號send
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功返回0,失敗返回-1
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgqid:消息隊列的id msgp:?定義結構體對象
msgsz:消息塊??
msgtyp:指定要接收的消息類型.如果msgtyp為0,
則接收隊列中的第?條消息(?論類型).
如果 msgtyp?于0,則接收類型等于msgtyp的第?條消息
msgflg:0
返回值:
成功時,msgrcv 返回接收到的消息的實際字節數
(不包括消息類型和消息長度字段)
失敗時,返回 -1,
7.信號量隊列常用接口概述
semget信號量的創建
int semget(key_t key, int nsems, int semflg);
key:ftok
nsems:指定要創建的信號量集中信號量的數量(user所需信號量數)
要保護的shm個數
semflg:IPC_CREATE,IPC_CREATE|IPC_EXCL
返回值:
成功時:semget 返回?個?負整數,即信號量集的標識符(semid)
這個標識符在后續對信號量的操作中會被?到。
失敗時:semget 返回 -1
semctl信號量的刪除
int semctl(int semid, int semnum, int cmd, ...);
semid:信號量集的標識符,通過 semget 函數獲得。
semnum:信號量的下標(從0開始)
cmd:指定要執?的控制操作的命令
... :取決于 cmd 的值,
這個參數可能是?個指向 union semun 的指?
該聯合體?于傳遞接收與命令相關的數據
?十二.信號量
IPC資源必須主動刪除 其?命周期隨內核 信號?不同于信號 信號量本質上是?個計數器
1.sem的pv操作
對多個信號量的pv操作(申請資源和釋放)
int semop(int semid, struct sembuf *sops, size_t nsops)
semid:通過semget?成的信號標識符
*sops:數組
nsops:數組個數
2.C語?使?繼承多態封裝的?式構建ipc
在OS層? IPC是同類資源
IPC資源?定是全局資源(變量)
3.查看ipc屬性
十三.信號的產?
1.
前臺進程受user的操作?擾:ctrl+z是終?前臺進程 后臺進程不會 依舊被解釋
如何讓后臺進程運??不顯示:nohup ./sig &
將該進程后臺運?并打印到nohup.out?件中去
1.設置信號處理函數signal
作?:?定義信號處理
typedef void (*sighandler_t)(int);
void (*sighandler_t)(int):函數指針類型
sighandler_t signal(int signum, sighandler_t handler);
signum:要處理的信號編號,可以寫?1-31號指令數字或指令
如,SIGINT表示中斷信號(由 Ctrl+C 產?),SIGTERM表示終?信號。
sighandler_t handler:輸?信號要考傳遞函數指針
返回值:
成功時,返回之前的信號處理程序的地址
(如果之前未設置,則可能是SIG_ERR或SIG_DFL)
失敗時,返回SIG_ERR,并設置errno以指示錯誤原因。
kill -l:信號查詢指令,1-31為重點 其本質為宏定義
2.signal的使?
默認終?->執??定義?法:Handler
SIGINT效果:按下ctrl+c后給前臺發送號信號后執?Handler函數
SIGQUIT效果:按下ctrl+\后給前臺發送3號信號后執?Handler函數
3.信號產?的三種?式
4.raise函數
發送信號給進程本身的函數
?int raise(int sig);
?int sig:這是要發送的信號。
使?信號進?進程終?
向??發送終?信號
有點類似于exit
void abort(void);
6) SIGABRT
5.OS如何通過信號知道CPU出錯
十四.信號的保存
1.信號的捕捉signal
2.信號的處理
delivery:信號處理也叫信號遞達
pending:產?到遞達之?家譜信號未決,也是信號保存
block:進程可以選擇阻塞特定信號,阻塞信號也叫屏蔽信號
信號?直處于pending狀態,會被保存起來
阻塞信號就是將信號置于等待處理的狀態
被阻塞的信號將保持在pending狀態
ps:忽略不等于阻塞,阻塞在遞達之前,忽略在遞達之后
signal_t也叫信號屏蔽字
信號操作函數:對信號集進??特位級別調整
delivery:信號處理也叫信號遞達
block(信號屏蔽字):block作?是屏蔽(阻塞某些信號)
修改block位圖,進程可以控制哪些信號到達,哪些信號忽略或延后處理(預設處理?法)
進程可以選擇阻塞特定信號(阻塞信號也叫屏蔽信號)
阻塞的信號會處于pending狀態,信號?直處于pending狀態,會被pending表保存起來
pending(未決信號集):?于保存被block的信號
產?到遞達之?家譜信號未決(進程?法接受或處理信號)
pending位圖?般?于記錄已發送到進程但未處理的信號(阻塞)
ps:忽略不等于阻塞,阻塞在遞達之前,忽略在遞達之后
signal_t也叫信號屏蔽字
handler:保存每個信號的處理?法
3.信號的保存位圖簡介
4.對信號block中屏蔽字的操作
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
讀取或更改進程的信號屏蔽字,對block表進?操作
how:
SIG_BLOCK將set中所有信號添加到block表中,阻塞這些信號
SIG_SETMASK將新的屏蔽字覆蓋到?的屏蔽字上(set)
SIG_UNBLOCK解除屏蔽
set:指定要更改的信號集
oldset:保存舊的信號屏蔽字,以便恢復
int sigpending(sigset_t *set);
獲取當前信號的pending信號集
set:這是?個指向 sigset_t 類型變量的指針
函數會將當前阻塞且未處理的信號集合寫?這個變量中、
十五.信號的處理
信號?般何時處理?
進程從內核態切回?戶態 監測當前進程的pending和block
決定是否結合handler表處理信號
1.信號處理流程簡圖
2.有關用戶態和內核態
3.信號處理函數signation
#include <signal.h>
int sigaction(int signum,
const struct sigaction *act, struct sigaction *oldact);
signum:要處理的信號編碼
act:指向?個struct sigaction結構體,
該結構體指定了新的信號處理?式
oldact:保存原有的信號處理?式
struct sigaction {void (*sa_handler)(int); //信號處理程序,不接受額外數據void (*sa_sigaction)(int, siginfo_t *, void *);//實時信號處理 略sigset_t sa_mask; //阻塞關?字的信號集int sa_flags; //影響信號的?為 默認為0int (*sa_restorer)(void);//略
};
4.可重?函數
可重?函數簡單定義
?個函數被兩個及其以上執?流重復進?
執?流是指程序在運?過程中的控制流程,即程序執?路徑或執?順序,其描述了程序指令被CPU執?的過程
哪些函數屬于可重入函數
1 使?了全局資源為不可重?函數
2 不使?任何全局資源 所有變量是臨時的 則此函數為可重?函數
九成函數皆為不可重?函數
函數名帶_r為可重?函數
5.易變關鍵字volatile
volatile?于告訴編譯器某個變臉的值可能在程序控制之外改變
這通常?于寄存器或內存映射的I/O 或?于多線程編程中共享變量
volatile可停?編譯器對該變量的優化 確保每次訪?該變量從其內存地址讀取其值
所以易變關鍵字?旦修飾某變量 則該變量變不可優化進?編譯器 以保持內存可?性
6.SIGCHILD
子進程退出時會給父進程發送信號SIGCHLD
signal(SIGCHLD, SIG_IGN) 對SIGCHLD進行忽略
在 Linux 和類 Unix 操作系統中,SIGCHLD 是一個信號,用于通知父進程其一個子進程的狀態已經發生了變化。
這個信號通常用于以下幾種情況:
-
子進程停止:當子進程停止(例如,因為接收到 SIGSTOP、SIGTSTP、SIGTTIN 或 SIGTTOU 信號)時,父進程會收到 SIGCHLD 信號。
-
子進程繼續運行:當之前停止的子進程繼續運行(例如,因為接收到 SIGCONT 信號)時,父進程也會收到 SIGCHLD 信號。
-
子進程退出:當子進程終止(調用 exit 或因為接收到致命信號而退出)時,父進程會收到 SIGCHLD 信號。
SIGCHLD 信號的處理通常涉及以下幾個方面的操作:
-
清理子進程資源:父進程可以通過 wait 或 waitpid 系統調用來獲取子進程的退出狀態,并釋放系統資源(例如,子進程的進程表項)。
如果父進程不調用 wait 或 waitpid,子進程會變成僵尸進程(zombie process),仍然占用系統資源。 -
監控子進程:父進程可以使用 SIGCHLD 信號來監控子進程的狀態,并根據需要進行相應的處理。
例如,如果子進程因為錯誤而退出,父進程可以記錄錯誤日志或重新啟動子進程。
在默認情況下,SIGCHLD 信號通常會被忽略(在某些系統上,如 Linux,默認行為是將其設置為 SIG_IGN)。
這意味著父進程不會自動收到這個信號的通知,除非它顯式地通過 signal 或 sigaction 函數來捕捉或設置這個信號的處理函數。
?進程不等待?進程
?進程執?獨?任務或?進程需要繼續執?任務時?進程等待?進程 ?過設置sigaction結構體中的sa_flags為SA_NOCLDWAIT, 使得?進程在?進程結束時不會收到SIGCHLD信號, 并且?進程的結束狀態會被?即丟棄,從??免產?僵?進程
?進程等待?進程
十六.線程
1.進程概念的formulate
定義:線程是進程內部的執?分? 進程是線程的容器
a:進程是承擔分成sys資源的基本實體
b:線程是sys調度的基本單位
?于劃分進程申請的各項sys資源
2.多線程的創建及其運?機制
3.OS的內存管理
頁表圖示
?級?表
MMU?作簡圖
缺頁中斷概述
缺?中斷的應?
new和malloc就是對虛擬地址空間申請
或對Heap擴容 并對?表維護
處理過程 所以申請內存本質是填充?表
處理過程 所以申請內存本質是填充?表
缺?中斷的處理過程包括以下?個步驟:
保存上下?:操作系統保存當前進程的上下?信息,以便在處理完缺?中斷后能夠恢復執?。
查找??:操作系統檢查該??是否已被換出(swapped out)到磁盤上的交換空間(swap space)或其他地?。
??調?:
如果??在交換空?中,操作系統會將其從磁盤讀?物理內存。
如果??根本不存在(如?法訪?),操作系統可能會引發?個錯誤并終?進程。
更新?表:將虛擬地址對應的??映射到物理內存中的新位置,并更新?表。
恢復上下?:恢復被中斷進程的上下?信息,并繼續執?被中斷的指令。
4.線程的控制及其周邊問題
Linux沒有線程的概念,其僅有LWP,線程是?LWP模擬的,所以Linux不會提供線程接?,僅提供創建LWP的接?vfork
LWP系統調?函數vfork()
#include <unistd.h>
pid_t vfork(void);
作?:創建?進程,和?進程共享地址空?
參數:不接受任何參數
返回值
成功時,vfork()在?進程中返回?進程的PID。
在?進程中返回0.這?點和fork函數?致
出?時,返回-1,并設置 errno 以指示錯誤類型。
fork和vfork是對clone函數的封裝
所以vfork創建出來的是?戶級線程
只有Windows有真正意義上的PCB和TCB
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...);
clone函數會根據參數flags接受到的選項來定奪
創建拷?空間?進程還是共享空間LWP
線程創建函數pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread_t *thread:這是?個指向 pthread_t 類型變量的指針
可看作主線程對新線程操作時使?的對象名
const pthread_attr_t *attr:
這是?個指向線程屬性對象的指?,可以傳遞 NULL,此時使?默認屬性
void *(*start_routine) (void *):也可看作是新線程執?任務的具體?式
回調函數,這是?個指向函數的指?,該函數是新線程的起始執?點
void *arg:
這是傳遞給 start_routine 函數的參數。它的類型和內容由程序員定義
如果成功,pthread_create返回0
如果失敗,它返回?個錯誤代碼(?零值)
pthread_create的使?
5.多線程
線程異常
線程出現指針之類的?誤會崩潰
隨之進程也會崩潰 此進程下的其它線程也崩潰
調?syscall觸發軟中斷系統回收進程資源
同?進程下 ?線程崩潰所有線程都崩潰
異常的本質就是觸發軟中斷 向?標進程發信號
線程等待和回收
線程創建之后也是需要等待和回收的
a.線程被創建后不等待會出現類似僵?進程的問題
ps 內存泄漏
b.為了知新線程的執?結果
使?pthread_join函數對?線程阻塞等待
#include <pthread.h>
#include <void.h>
int pthread_join(pthread_t thread, void **retval);
作?:主線程等待新線程 和wait作??樣 回收新線程占?的資源
thread:要等待的線程的標識符(ID),常是通過 pthread_create 函數獲得的。
retval:?個指向指針的指針,?于接收?標線程的返回值。
如果不需要接收返回值,可以將其設置為NULL。
detach新線程后 若主線程退出 誰來維護新線程?
detach后 新線程與主線程的關聯取消
新線程會成為后臺線程或守護線程
成為后臺線程時將由運?時庫接管
PCB退出時也?并由系統內核釋放
如何理解pthread_create的第三參數與第四參數
void意思是類型不完整 ?般??為0字節 但是void*??為8字節
函數返回類型是void時不需要任何返回值 但是如果是void*就需要返回值nullptr
線程創建是異步的
pthread_create 函數調?是異步的
這意味著主線程不會等待新線程開始執?才繼續執?下?條指令
相反 pthread_create 會在為新線程分必要的資源并設置其執?函數后?即返回新線程的執?是獨?于主線程的
并且其執?順序與 pthread_create 的調?順序沒有必然的聯系
如何理解pthread_join第?參數
作?:?于存儲pthread_create中回調函數routine的返回值
多線程資源訪問權限
?
線程退出pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
作?:單?進程退出
retval:新線程返回值,由pthread_join函數填寫
線程取消pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
取消?個線程的前提是?標進程已啟動
作?:由主控線程去取消其他線程 不推薦使?
發送?個請求使線程狀態變為待處理 但不?即終?線程執?
thread:這是要發送取消請求的線程標識符
線程分離detach:主線程不等待新線程
和?進程與?進程類似
當主線程有??的任務需要執?時,主線程可以不等待新線程
可以將?標線程設置為分離狀態
joined:線程需要被join(default)
detach:線程分離(主線程不等待新線程)
多執?流情況下,保證主執?流最后退出
#include <pthread.h>
int pthread_detach(pthread_t thread);
thread:要分離的線程的標識符,該標識符是pthread_create函數調?時返回的線程ID
返回值:如果成功,函數返回0;如果失敗,函數將返回?個?零錯誤碼
作?
pthread_detach函數的主要作?是將線程從可結合(joinable)狀態轉換為可分離狀態
在可分離狀態下,線程在終?時會?動釋放其占?的系統資源
??需其他線程調?pthread_join函數來回收這些資源
//如果pthread_detach和pthread_join共存,那么主線程依舊會等待新線程
//如果只有pthread_join,那么主線程也會依舊等待新線程
//如果只有pthread_detach,那么主線程會忽視新線程,任由新線程執???的任務
進程內可以創建線程 線程內可以創建進程 只要fork和pthread相關函數使?合理即可
十七.線程庫
1.?戶級線程庫成結構簡析
2.C++中對POSIX內核級線程庫接?封裝邏輯理解
對POSIX內核級線程庫接?封裝?輯理解 假設有?個Thread 先?class描述?再組織
線程狀態枚舉與成員
線程創建
ps:據規定,
?定義函數Routine參數列表有且僅有?個void*類型變量
?class中的所有函數參數列表默認?帶*this
所以 使?static來取消this
構造函數
線程停?
線程等待資源回收
線程分離
線程互斥
臨界資源 多執?流被保護的資源
臨界區(代碼) 每個線程內存訪問臨界資源的代碼 僅?個線程可訪問
互斥 任何時候,保證有且僅有?個執?流進?臨界區
原?性 不會被任何調度機制打斷的操作,有且僅有完成和未完成兩態
互斥變量Mutex
?于保證共享資源被?個進程或線程訪問的變量
未加保護的共享資源 線程并發問題演示
有關執?結果為何會有負數的分析
為什么ticketnum最后會變負數
因為if判斷不具有原?性
多個線程在?個cpu上同時運?,它們同時將ticketnum讀取到了cpu上并進
?--操作就導致了ticketnum被多減了好幾遍(多執?流)
讓線程合理切換可以較好地解決此?題,線程?般什么時候切換
a.線程時間?耗盡
b.來了優先級更?的進程(OS線程是基于優先級搶占的)
c.通過usleep從內核返回?戶時,會進?時??是否耗盡的判斷,進?切換
數據從內存搬到cpu寄存器本質是將數據從共享變為線程私有 寄存器內容叫做執?流硬件上下?、
原?性性狀有且僅有執?前和執?后兩態 不存在執?中此態
使?互斥鎖Mutex對臨界區保護解決上述問題
臨界區與?臨界區
所有對臨界資源的保護?是對臨界代碼的保護 因為只有通過臨界代碼才能訪問臨界資源
臨界資源:?次僅允許?個執?流訪?的共享資源 共享性:多個執?流可以訪問
互斥性:任何時刻僅允許?個執?流訪問
有關lock的相關接?操作簡介
#include <pthread.h>
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; 聲明?個lock并初始化
int pthread_mutex_lock(pthread_mutex_t *lock);//加lock
如果當前lock被其他線程占有,就讓此線程阻塞式等待int pthread_mutex_trylock(pthread_mutex_t *mutex);//加lock
如果當前lock被其他線程占有,就讓此線程?刻返回?不是阻塞式等待int pthread_mutex_unlock(pthread_mutex_t *lock);//解lockint pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
作?:?于初始化 POSIX 線程(pthread)互斥lock(mutex)的函數
pthread_mutex_t *mutex:互斥lock的地址或指針
const pthread_mutexattr_t *attr:指向互斥lock屬性的指針
如果傳遞 NULL,則使?默認屬性
返回01int pthread_mutex_destroy(pthread_mutex_t *mutex);
作?:對上述初始化的1lock銷毀
全局lock(互斥)的使?
lock實現原理
也可以依靠硬件實現加lock
通過屏蔽中斷達到延時間?的效果
(每執行一條指令以后都要去檢測是否有中斷,如果有中斷那么這個中斷就完全有可能是其他的執行流,現在當我正在執行某個方法中的所有指令時屏蔽所有中斷以遏制這一情況的發生)
這樣指定線程就不會被切換
代碼執?結束后再開啟時中斷
C++11?格的lock
對系統調?lock接?封裝
線程同步
互斥保證安全性 但未必合理或?效 同步是在安全的前提下保證更加合理
條件變量(同步)
條件變?是?個?來進?進程同步的特性 內?要維護線程隊列
為了保證?個線程在臨界區內頻繁申請mutex從?導致不執?臨界資源?題
我們便將此mutex設置為條件變量確保臨界區內的線程?直去執?任務
條件變量允許?個或多個線程在條件不滿?時進?等待狀態
直到另?個進程修改了此條件
修改后它會通過pthread_cond_signal或pthread_cond_broadcast通知等待線程
當條件變量被觸發時,?或多個等待條件變量的線程就會被喚醒
線程被喚醒后會去?動獲取之前被釋放的lock
獲取lock后會再次檢查條件變量所依賴的條件,查看條件變量是否滿?
滿?則線程訪問臨界資源
反之繼續等待返回等待隊列繼續等待
條件變量操作所涉及到的?些必要POSIX接?
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
作?:?于初始化?個條件變量。條件變量?于線程?的同步,允許?個或多個線程在某個條件滿?時被喚醒。
cond:指向需要初始化的條件變量的指?。
attr:指向條件變量屬性的指針,常可以傳遞 NULL 以使?默認屬性。
?
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
作?:使當前線程進?等待隊列,讓線程等待條件變量的變化,通常和mutex?起使?,以保證操作的原?性
cond:指向條件變量的指針。
mutex:指向互斥鎖的指針,調?線程在調? pthread_cond_wait 前必須已經持有該lock
函數會?動釋放鎖并在條件變量被觸發后新獲取鎖。
?
int pthread_cond_signal(pthread_cond_t *cond);
作?:?于?個等待某個條件變量的線程,如果有多個線程在等待該條件變?,則選擇其中?個喚?
cond:指向條件變量的指針
int pthread_cond_broadcast(pthread_cond_t *cond);
作?:?次喚醒所有線程 ?者作?是喚醒線程去看看能不能執?任務,如果線程發現不能執?任務就會被pthread_cond_wait阻擋
?線程
?次喚醒?個線程
?次喚醒所有線程
十八.生產者 消費者模型簡要概述
基于?產消費模型的POSIX計數信號?理解控制使?與封裝
信號量本質上是?個計數器 ?于記錄?個thread對臨界資源的與定數 記錄是否有thread在訪?臨界資源
信號量和mutex?樣 其本身具有臨界性與原?性
所以說mutex也是信號量的?種特殊情況
使?時 我們只需記好信號量???是?于表示隊列中的空間和隊列中的有效數據的的變量
另???信號量下的控制下線程的獲取和釋放操作具有原?性 保證了其操作不會被其他線程打斷
信號量定義與類型
信號量是?種計數器,?于控制對共享資源的訪問
它本質上是?個整型變量,可以通過特定的操作進?訪問和修改
信號量主要分為兩種類型:
計數信號量(Counting Semaphore):其值可以表示多個可?資源的數量,
?于控制多個進程或線程對多個資源的并發訪問。
?進制信號量(Binary Semaphore),?稱互斥量(Mutex):其值只能為0
或1,?于實現互斥訪問即同?時間內只允許?個進程或線程訪問某個資源
信號?常?POSIX接?介紹
對sem封裝
有關構?函數的參數列表和初始化列表以及函數體是哪些變量的初始化領域
相同點就是三者是對成員變量進?初始化
不同點是
參數列表?般是需要user主動傳參的,或者是某個成員變量需要user?動傳參且共享同?參數
初始化列表則?般接受來?參數列表變量的初始化或者user既定的默認值
且user使?此類類型進?對象創建時只能對其構?函數的參數列表中的成員變量進?初始化
構?函數體內?般是某個成員變量初始化需要其他函數對其進?初始化的變量的初始化區域
?
?
?
?