wordpress在線音樂/seo狂人
目錄
一、基本概念
二、描述進程-PCB
1、task_struct-PCB的一種
2、task_ struct內容分類
三、組織進程
四、查看進程
1、ps指令
2、top命令?
3、/proc文件系統(tǒng)
4、在/proc文件中查看指定進程
5、進程的工作目錄?
五、通過系統(tǒng)調用獲取進程標示符
1、getpid()/getppid()?
getpid()
getppid()
2、kill命令
五、通過系統(tǒng)調用創(chuàng)建進程
1、bash
2、fork()
父子進程返回結果不同?
?fork之后有兩個不同的執(zhí)行流
fork創(chuàng)建進程后,為什么會有兩個返回值?
3、總結:
一、基本概念
程序的本質是文件,以二進制形式存儲在磁盤中。當程序文件加載到內存時,就形成了一個進程。因此,操作系統(tǒng)幫助我們將程序轉換為進程,以執(zhí)行特定任務。簡單來說,每次打開一個程序或應用時,都會生成一個對應的進程。
- 教材概念:程序的一個執(zhí)行實例,正在執(zhí)行的程序等
- 內核觀點:擔當分配系統(tǒng)資源(CPU時間,內存)的實體。
?進程=程序的代碼和數據(磁盤)+操作系統(tǒng)維護的進程控制塊(PCB)結構體
進程是計算機中正在運行的程序的實例,它包括了程序的代碼和數據(存儲在磁盤上),以及操作系統(tǒng)維護的進程控制塊(PCB)結構體。
- 代碼指的是程序的指令集合,定義了程序的邏輯和執(zhí)行流程。這些指令存儲在磁盤上的可執(zhí)行文件中。當進程被加載到內存中運行時,這些指令被復制到內存中的代碼段中,并由處理器執(zhí)行。代碼段通常包括程序的可執(zhí)行指令、函數、子程序等。
- 數據指的是程序在運行過程中使用的變量、常量、對象等存儲數據。數據存儲在進程的數據段中,也就是進程的內存空間中的一部分。數據段包括全局變量、靜態(tài)變量、堆、棧等。
- 這些代碼和數據構成了進程的執(zhí)行環(huán)境,使得程序能夠在計算機上正確運行。除了代碼和數據外,進程還包括了操作系統(tǒng)維護的進程控制塊(PCB)。PCB是用于存儲和管理進程的各種信息的數據結構,如進程的狀態(tài)、優(yōu)先級、寄存器值、內存分配情況等。PCB存儲了進程的標識、狀態(tài)、優(yōu)先級、程序計數器(PC)值、寄存器內容、內存分配情況等重要信息,是操作系統(tǒng)用于管理和控制進程的關鍵數據結構。
二、描述進程-PCB
在Windows任務管理器中,我們可以看到許多正在運行和后臺運行的進程。操作系統(tǒng)需要對這些進程進行管理,這是通過一種稱為進程控制塊(PCB)的數據結構來實現的。PCB包含了進程的屬性信息,類似于文件的內容和屬性。
- 進程信息被放在一個叫做進程控制塊的數據結構中,可以理解為進程屬性的集合。
- 課本上稱之為PCB(process control block),Linux操作系統(tǒng)下的PCB是: task_struct
1、task_struct-PCB的一種
- task_struct是Linux內核的一種數據結構,它會被裝載到RAM(內存)里并且包含著進程的信息
2、task_ struct內容分類
- 標示符: 描述本進程的唯一標示符,用來區(qū)別其他進程。
- 狀態(tài): 任務狀態(tài),退出代碼,退出信號等。
- 優(yōu)先級: 相對于其他進程的優(yōu)先級。(優(yōu)先級:先后順序,權限:能與不能)
- 程序計數器: 程序中即將被執(zhí)行的下一條指令的地址。
- 內存指針: 包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針。
- 上下文數據: 進程執(zhí)行時處理器的寄存器中的數據[休學例子,要加圖CPU,寄存器]。
- I/O狀態(tài)信息: 包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表。
- 記賬信息: 可能包括處理器時間總和,使用的時鐘數總和,時間限制,記賬號等。
- 其他信息
三、組織進程
- 有些操作系統(tǒng)會把任務隊列稱為任務數組。但是Linux實現時使用的是隊列而不是靜態(tài)數組,所以稱為任務隊列.
四、查看進程
新創(chuàng)建一個myproc.c文件,為其編寫一個Makefile文件對其進行編譯,然后運行myproc這個死循環(huán)的可執(zhí)行程序方便持續(xù)查看進程。?
1、ps指令
ps
?指令是 Linux 中用于顯示當前正在運行的進程的命令。它提供了有關進程的各種信息,例如進程的 PID(進程標識符)、CPU 和內存使用情況等。
- 默認情況下,如果你只輸入?
ps
?命令而不加任何選項,它會顯示與當前終端會話相關的進程信息。這可能包括 Shell 以及你通過該 Shell 啟動的其他進程。
ps axj | grep 'myproc'
- 這個命令是將兩個命令結合起來使用,首先執(zhí)行?
ps axj
?命令,它會顯示所有進程的詳細信息。然后使用管道?|
?將輸出傳遞給?grep 'myproc'
?命令,grep
?是用于搜索指定模式的文本的工具。- 因此,
ps axj | grep 'myproc'
?命令的作用是從所有進程的詳細信息中過濾出包含字符串?'myproc'
?的行。這樣就能找到與?'myproc'
?相關的進程信息。a
?選項表示顯示所有用戶的進程,而不僅僅是當前用戶的進程。x
?選項表示顯示沒有控制終端的進程,即顯示所有進程而不僅僅是與當前終端關聯的進程。j
?選項表示以作業(yè)控制的格式顯示進程信息,這種格式通常包括更多關于進程的詳細信息。
ps axj | head -1 && ps axj | grep 'myproc'
- 首先執(zhí)行?
ps axj
?命令,它會顯示所有進程的詳細信息。然后使用管道?|
?將輸出傳遞給?head -1
?命令,head -1
?只會顯示輸出的第一行,即列標題行,這樣可以讓我們看到列的含義。- 接著,
&&
?運算符表示如果前一個命令成功執(zhí)行(即返回狀態(tài)碼為 0),則執(zhí)行下一個命令。因此,如果第一個命令成功執(zhí)行,就會繼續(xù)執(zhí)行第二個命令。- 第二個命令是?
ps axj | grep 'myproc'
,它會從所有進程的詳細信息中過濾出包含字符串?'myproc'
?的行。這樣就能找到與?'myproc'
?相關的進程信息。
2、top命令?
top
?命令是一個交互式的實用程序,用于動態(tài)監(jiān)視系統(tǒng)的進程活動和資源利用情況。它可以顯示各個進程的 CPU 占用、內存占用、以及其他系統(tǒng)資源的使用情況。top
?命令提供了一個實時更新的進程列表,用戶可以通過鍵盤命令與其交互,例如排序進程、終止進程等。下面是一些常用的?
top
?命令的鍵盤快捷鍵:
q
:退出?top
?命令。k
:終止進程。輸入該命令后,會提示輸入需要終止的進程的 PID。Space
:更新顯示。1
:切換到顯示每個 CPU 核心的獨立信息。M
:按內存使用量排序。P
:按 CPU 使用量排序。T
:按時間排序。
top
?命令的輸出通常包括:
- 系統(tǒng)概述:系統(tǒng)的運行時間、平均負載等。
- 進程信息:各個進程的 PID、CPU 使用率、內存使用量等。
- 系統(tǒng)資源:CPU 使用率、內存使用情況、交換分區(qū)使用情況等。
3、/proc文件系統(tǒng)
進程的信息可以通過 /proc 系統(tǒng)文件夾查看,/proc
?是一個特殊的虛擬文件系統(tǒng),用于在Linux系統(tǒng)中提供進程和系統(tǒng)信息。雖然它在文件系統(tǒng)中顯示為一個目錄,但實際上它是一個由內核動態(tài)生成的虛擬文件系統(tǒng),用于向用戶空間提供系統(tǒng)和進程的信息。通過訪問?/proc
?目錄,可以查看和管理運行中的進程,以及獲取有關系統(tǒng)狀態(tài)和配置的信息。
ls /proc
- 這個目錄是動態(tài)的,多一個進程就多一個目錄,少一個進程就少一個目錄。
ls /proc -l???
4、在/proc文件中查看指定進程
查找?myproc
?進程:?
ps axj | grep myproc
?使用?
ps axj
?命令列出所有進程的詳細信息,然后用?grep
?過濾出包含?myproc
?的行。輸出顯示?myproc
?進程的 PID 是 24857,同時也顯示了運行?grep
?命令本身的進程信息。
在?/proc
?目錄中查找進程:?
ls /proc -l | grep '24857'
?這個命令列出了?
/proc
?目錄的內容,并使用?grep
?查找與?myproc
?進程 PID(24857)相關的目錄。/proc
?文件系統(tǒng)包含了系統(tǒng)信息和正在運行的每個進程的詳細信息。每個進程都有一個以其 PID 命名的目錄。輸出顯示了 PID 為 24857 的進程的目錄。
列出?/proc/24857
?目錄的內容:?
ls /proc/24857
??通過列出?
/proc/24857
?目錄的內容,可以看到與進程相關的許多文件和目錄。這些文件和目錄提供了關于進程的各種信息,包括:
cmdline
:進程啟動命令。cwd
:進程的當前工作目錄。environ
:進程的環(huán)境變量。exe
:到啟動進程的可執(zhí)行文件的符號鏈接。fd
:包含指向進程打開的文件描述符的符號鏈接。status
:進程的狀態(tài)信息。mem
:進程的內存映射。- 等等其他許多提供關于進程運行狀態(tài)、資源使用情況等信息的文件和目錄。
5、進程的工作目錄?
其中cwd表示當前進程的工作目錄
以前學習的FILE *fp = fopen("log.txt","w"),第一個參數沒有帶路徑,默認打開當前路徑。為什么呢?
這是因為我們的程序經過編譯形成可執(zhí)行程序,打開文件運行后,形成一個進程,每個進程都會有一個屬性,來保存自己的工作路徑。
五、通過系統(tǒng)調用獲取進程標示符
1、getpid()/getppid()?
?使用man手冊查看使用方法?
getpid()
- 功能:
getpid()
?函數用于獲取當前進程的進程 ID(PID)。 - 返回值:它返回一個?
pid_t
?類型的值,即當前進程的 PID。在 Linux 中,每個運行的進程都有一個唯一的進程標識符,用于區(qū)分不同的進程。 - 使用場景:該函數在需要根據進程 ID 進行進程管理或信息記錄時非常有用。例如,日志記錄時可能需要記錄發(fā)起日志條目的進程 ID。
getppid()
- 功能:
getppid()
?函數用于獲取當前進程的父進程的進程 ID(PPID)。 - 返回值:同樣返回一個?
pid_t
?類型的值,即當前進程的父進程的 PID。當一個進程被創(chuàng)建(通常是通過?fork()
?調用)時,創(chuàng)建它的進程成為其父進程。 - 使用場景:這在需要了解或控制進程的層級結構時非常有用,比如,在創(chuàng)建守護進程時,可能會根據父進程的 ID 進行特定的邏輯判斷。
下面我們創(chuàng)建一個myproc.c文件,輸出的pid與我們查詢的進程id進行比較:?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{while(1){pid_t id=getpid(); //獲取的是自己的進程printf("hello world,pid: &d\n",,id);sleep(1);}return 0;
}
右邊復制一個SSH渠道,邊運行邊查看,如下圖:
我們可以發(fā)現右邊通過getpid成功輸出進程myproc的pid。?
我們再輸出一下父進程id(ppid)?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{while(1){pid_t id=getpid();printf("hello world, pid: %d, ppid: %d\n",id,getppid());sleep(1);}return 0;
}
輸出結果 :
2、kill命令
?kill
?命令用于向進程發(fā)送信號,以控制進程的行為或終止進程。它的基本語法是:?
kill [options] <PID>
其中?<PID>
?是要終止的進程的進程標識符。
常用的?kill
?命令選項包括:
-l
:列出可用的信號名稱。-9
:發(fā)送強制終止信號,也稱為 SIGKILL,立即終止目標進程。-15
:發(fā)送終止信號,也稱為 SIGTERM,默認行為是終止目標進程,但它可以被進程捕獲、忽略或處理。-SIG<signal>
:使用信號名稱來指定要發(fā)送的信號,例如?-SIGTERM
。
例如,要終止PID為22053的進程,操作如下:
五、通過系統(tǒng)調用創(chuàng)建進程
1、bash
每次查詢當前運行的命令時,我們知道子進程是我們創(chuàng)建并運行的,那父進程是誰?
- 父進程是bash。
系統(tǒng)中,每個命令行上運行的命令都是由 Bash shell 的一個子進程執(zhí)行。此外,Bash shell 本身也是系統(tǒng)中許多進程的父進程。 Bash shell 是命令行界面的核心,負責解釋和執(zhí)行用戶輸入的命令。
復習Shell概念?
- Shell(外殼)是計算機操作系統(tǒng)中的一個用戶界面,用于與操作系統(tǒng)內核進行交互。Shell允許用戶通過命令行或圖形用戶界面(GUI)來執(zhí)行操作系統(tǒng)提供的功能和應用程序。Shell接受用戶輸入的命令,并將其解釋并傳遞給操作系統(tǒng)內核執(zhí)行。
- 在類Unix操作系統(tǒng)(如Linux、macOS等)中,常見的Shell包括Bash(Bourne Again Shell)、Zsh(Z Shell)、Fish等。這些Shell提供了豐富的命令和功能,使用戶能夠管理文件、運行程序、配置系統(tǒng)等操作。
在大多數Linux系統(tǒng)中,常用的命令行解釋器(shell)是Bash(Bourne Again Shell)。Bash是一個流行的Unix shell,也是許多Linux發(fā)行版的默認shell。它提供了豐富的功能和命令,使用戶能夠與操作系統(tǒng)進行交互、執(zhí)行命令、編寫腳本等。
如果我們kill -9 bash呢?
kill -9 加上bash的id ,命令行會會失效。
-
立即終止會話:?當前終端或會話中的Bash進程會被立即終止,導致您失去對該終端會話的訪問。
-
子進程可能被終止:?如果該Bash進程啟動了任何子進程,那么這些進程可能也會因為父進程的終止而受到影響,除非它們已經被設置為守護進程或與終端會話分離。
-
未保存的數據丟失:?如果您在該Bash會話中運行的程序或編輯器中有未保存的工作,強制終止Bash進程將導致這些數據丟失。
-
不影響其他Bash會話:?如果您在同一系統(tǒng)上打開了多個終端會話,這個操作只會影響您向其發(fā)送
kill -9
命令的那個Bash進程。其他Bash會話及其子進程將不受影響。 -
可能需要重新登錄:?終止當前會話的Bash進程后,您可能需要重新打開一個新的終端會話或重新登錄您的用戶賬戶來恢復正常操作。
- 注意:每次登入的bash都不同,復制一個SSH通道,殺掉bash進程,不會影響另一個窗口運行命令。
2、fork()
在Linux系統(tǒng)中,
fork()
?是一個系統(tǒng)調用,用于創(chuàng)建一個新的進程。調用?fork()
?后,操作系統(tǒng)會復制當前進程的副本,包括代碼段、數據段、堆棧等,然后在新的進程中運行。原始進程被稱為父進程,新創(chuàng)建的進程被稱為子進程。
- 在?
fork()
?調用后,父進程和子進程會繼續(xù)執(zhí)行后續(xù)的代碼,但是它們會有不同的進程ID(PID)和返回值。在父進程中,fork()
?返回子進程的PID,而在子進程中,fork()
?返回0。 - 通過?
fork()
?創(chuàng)建子進程后,父子進程之間會共享一些資源,如文件描述符、內存映射等,但各自有獨立的地址空間。這樣可以實現并發(fā)執(zhí)行,父子進程可以在獨立的執(zhí)行環(huán)境中運行不同的任務。?
按照順序先運行沒有fork的代碼,再運行有fork的版本。?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{printf("I am parent process.\n");printf("you can see me.\n");return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{printf("I am parent process.\n");fork();printf("you can see me.\n");sleep(1);return 0;
}
?輸出結果如下:我們可以發(fā)現創(chuàng)建子進程后有一句被輸出了兩次。
?
這是因為創(chuàng)建進程后,變?yōu)閮蓚€程序,一個是父進程,另一個是子進程,他們分別運行fork()后面的程序。
父子進程返回結果不同?
我們再觀察下面代碼的輸出結果?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{printf("I am parent process.\n");pid_t ret=fork();printf("ret: %d, pid: %d, ppid: %d\n",ret,getpid(),getppid());sleep(1);return 0;
}
fork為什么給父進程返回子進程pid,給子進程返回0?
- 當
fork()
在父進程中被調用時,它會返回子進程的PID(進程ID),這樣父進程就可以知道新創(chuàng)建的子進程的PID,從而可以對子進程進行管理或跟蹤。 - 當
fork()
在子進程中被調用時,它會返回0,這樣子進程可以通過返回值來確定自己是子進程,而不是父進程。子進程可以根據返回值執(zhí)行自己的邏輯,而不是繼續(xù)執(zhí)行父進程的代碼。
?fork之后有兩個不同的執(zhí)行流
為什么下面else if和else可以同時輸出呢?因為fork之后有兩個不同的執(zhí)行流 。
#include <stdio.h>
#include <unistd.h>int main()
{pid_t id=fork();if(id<0){//創(chuàng)建失敗perror("fork");return 1;}else if(id==0){//child processwhile(1){printf("I am child, pid:%d, ppid:%d\n",getpid(),getppid());sleep(1);}}else{//parent processwhile(1){printf("I am father, pid:%d, ppid:%d\n",getpid(),getppid());sleep(1);} }printf("you can see me\n");sleep(1);//進程退出順序不一樣return 0;
}
?我們通過下面命令是用來監(jiān)視名為"myproc"的進程。
while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep; sleep 1; done
這是一個無限循環(huán)(
while :; do ... done
),在循環(huán)內部,它首先使用?ps axj | head -1
?命令來顯示進程列表的標題行(列名),然后通過?ps axj | grep myproc | grep -v grep
?命令來顯示包含 "myproc" 的進程,同時使用?grep -v grep
?來排除 grep 進程本身。最后,sleep 1
?用于每秒暫停一次
我們可以為每次輸出結果之間加上一條分割線。(###分隔符過長僅保留部分)
while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep; sleep 1; echo "###"; done
fork創(chuàng)建進程后,為什么會有兩個返回值?
- Linux中的
fork()
系統(tǒng)調用返回兩次值,這是因為在Unix系統(tǒng)中,fork()
的設計是基于父子進程的概念。調用fork()
時,操作系統(tǒng)會復制當前進程,創(chuàng)建一個新的子進程。這個子進程是父進程的副本,但它們是兩個獨立的進程,各自有自己的地址空間。 fork()
創(chuàng)建進程后返回兩次值的原因是,在fork()
內部,父進程和子進程各自會執(zhí)行自己的return語句,這導致了兩次返回。這并不意味著操作系統(tǒng)保存了兩次狀態(tài),而是因為父進程和子進程在不同的執(zhí)行上下文中各自返回。
3、總結:
- 在操作系統(tǒng)中,當需要運行一個進程時,實際上是從任務結構(
task_struct
)形成的隊列中選擇一個任務結構來執(zhí)行該進程的代碼。進程調度實質上就是在任務結構隊列中選擇一個進程的過程。 - 在創(chuàng)建父子進程后,哪個進程先運行并不確定。這是由操作系統(tǒng)的調度器決定的。調度器會根據一定的策略(如優(yōu)先級、時間片輪轉等)來決定下一個要運行的進程。
- 因此,父子進程的執(zhí)行順序不確定,取決于操作系統(tǒng)的調度算法。