【Linux篇】進(jìn)程入門指南:操作系統(tǒng)中的第一步

探索進(jìn)程世界:初學(xué)者必備的操作系統(tǒng)概念 前言

在計(jì)算機(jī)系統(tǒng)中,進(jìn)程是程序執(zhí)行的基本單元。它不僅是代碼的集合,還是操作系統(tǒng)管理和分配資源的核心對(duì)象。每當(dāng)我們啟動(dòng)一個(gè)應(yīng)用程序,操作系統(tǒng)便會(huì)為其創(chuàng)建一個(gè)進(jìn)程,使程序能夠獨(dú)立運(yùn)行并進(jìn)行資源管理。理解進(jìn)程的概念對(duì)深入學(xué)習(xí)操作系統(tǒng)和高效利用計(jì)算機(jī)資源至關(guān)重要。接下來(lái),我們將深入探討進(jìn)程管理的各個(gè)方面。

一. 馮·諾依曼體系結(jié)構(gòu)【Linux篇】進(jìn)程入門指南:操作系統(tǒng)中的第一步1.1 背景與歷史馮·諾依曼體系結(jié)構(gòu)是現(xiàn)代計(jì)算機(jī)的基礎(chǔ)設(shè)計(jì)模型,由約翰·馮·諾依曼在1945年提出。其核心思想是將程序和數(shù)據(jù)存儲(chǔ)在同一個(gè)內(nèi)存中,計(jì)算機(jī)通過(guò)中央處理單元(CPU)按順序執(zhí)行指令。在此向這位偉大的人物致敬。?

1.2 組成部分中央處理器(CPU)由運(yùn)算器和控制器組成。存儲(chǔ)器(內(nèi)存)是CPU進(jìn)行讀取和獲取數(shù)據(jù)的必要工具,CPU執(zhí)行程序時(shí),必須先將代碼及數(shù)據(jù)加載到內(nèi)存中,然后執(zhí)行代碼并訪問(wèn)數(shù)據(jù)。

1.3 意義其意義在于簡(jiǎn)化了計(jì)算機(jī)設(shè)計(jì),提升了計(jì)算機(jī)的可編程性,使得通過(guò)修改存儲(chǔ)器中的指令和數(shù)據(jù)可以實(shí)現(xiàn)多種功能。馮·諾依曼體系結(jié)構(gòu)成為現(xiàn)代計(jì)算機(jī)系統(tǒng)的標(biāo)準(zhǔn)架構(gòu),推動(dòng)了計(jì)算機(jī)技術(shù)的快速發(fā)展。

二. 進(jìn)程2.1 進(jìn)程概念進(jìn)程是程序的一次執(zhí)行實(shí)例,是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。它擁有獨(dú)立的內(nèi)存空間、系統(tǒng)資源(如文件句柄、網(wǎng)絡(luò)端口)以及運(yùn)行狀態(tài)。

2.1.1 PCB(進(jìn)程控制塊)task_struct包含部分信息,另一部分信息將在后續(xù)博客中詳細(xì)講解。

操作系統(tǒng)如何管理各種進(jìn)程?首先是描述,然后是組織。所有運(yùn)行的進(jìn)程都以task_struct鏈表的形式存在于內(nèi)核中。

【Linux篇】進(jìn)程入門指南:操作系統(tǒng)中的第一步2.2 查看進(jìn)程2.2.1 使用系統(tǒng)文件查看命令格式:

功能:查看指定進(jìn)程的進(jìn)程信息。不指定pid則查看所有進(jìn)程的信息。

2.2.2 使用top和ps等用戶級(jí)工具獲取命令格式:

ps ajx | grep myprocess | grep -v grep2.2.3 通過(guò)系統(tǒng)調(diào)用獲取進(jìn)程標(biāo)識(shí)符代碼語(yǔ)言:JavaScript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制“`javascript

include #include #include int main(){printf(“pid: %dn”, getpid());printf(“ppid: %dn”, getppid());return 0;}

 getpid()系統(tǒng)調(diào)用,用于獲取當(dāng)前進(jìn)程的PID(進(jìn)程ID),在子進(jìn)程中調(diào)用getpid()返回的是子進(jìn)程自身的PID。getppid()系統(tǒng)調(diào)用,用于獲取當(dāng)前進(jìn)程的父進(jìn)程PID。2.3 創(chuàng)建子進(jìn)程示例代碼: <p>代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0<svg fill="none" height="16" viewbox="0 0 16 16" width="16" xmlns="<a href="https://www.php.cn/link/c9041cfd2a40932691855abd98fd219a">http://www.w3.org/2000/svg"><path</a> d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運(yùn)行<svg fill="none" height="16" viewbox="0 0 16 16" width="16" xmlns="<a href="https://www.php.cn/link/c9041cfd2a40932691855abd98fd219a">http://www.w3.org/2000/svg"><path</a> clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor" fill-rule="evenodd"></path></svg>復(fù)制```javascript</p><h1>include<stdio.h>#include<unistd.h>#include <sys>int gval = 100;int main(){printf("父進(jìn)程開始運(yùn)行 ,pid: %dn",getpid());pid_t id = fork();if(id  %d", gval,  gval+10);gval+=10;printf("我是一個(gè)子進(jìn)程 !, 我的pid:%d, 我的父進(jìn)程id:%dn",getpid(),getppid());}}else{//fatherwhile(1){sleep(1);printf("我是一個(gè)父進(jìn)程 !, 我的pid:%d, 我的父進(jìn)程id:%d, gval: %dn",getpid(),getppid(),gval);}}printf("進(jìn)程開始運(yùn)行 ,pid: %dn",getpid());return 0;}</sys></unistd.h></stdio.h>

子進(jìn)程會(huì)共享父進(jìn)程的代碼和數(shù)據(jù),如果父子任何一方對(duì)數(shù)據(jù)進(jìn)行修改,操作系統(tǒng)會(huì)在底層對(duì)數(shù)據(jù)進(jìn)行拷貝,讓目標(biāo)進(jìn)程修改這個(gè)拷貝。

問(wèn)題1:為什么fork給父子返回各自不同的返回值?

父進(jìn)程中的返回值:fork() 在父進(jìn)程中返回子進(jìn)程的PID(進(jìn)程ID)。這個(gè)PID是一個(gè)正整數(shù),唯一標(biāo)識(shí)子進(jìn)程。父進(jìn)程可以使用該P(yáng)ID來(lái)跟蹤子進(jìn)程,執(zhí)行如等待子進(jìn)程結(jié)束、獲取子進(jìn)程的狀態(tài)等操作。

子進(jìn)程中的返回值:在子進(jìn)程中,fork()返回0。子進(jìn)程通過(guò)這個(gè)返回值可以判斷自己是否是子進(jìn)程,父進(jìn)程通過(guò)返回值判斷是否是父進(jìn)程。

問(wèn)題2:為什么一個(gè)函數(shù)會(huì)返回兩次?

父進(jìn)程的情況:返回值是子進(jìn)程的PID(進(jìn)程ID),是一個(gè)正整數(shù)。

父進(jìn)程用這個(gè)PID來(lái)識(shí)別和管理子進(jìn)程。父進(jìn)程可以使用這個(gè)PID來(lái)執(zhí)行如wait()、waitpid()等系統(tǒng)調(diào)用,等待子進(jìn)程終止或獲取子進(jìn)程的退出狀態(tài)。

子進(jìn)程的情況:返回值是0。

子進(jìn)程用返回值0來(lái)判斷自己是子進(jìn)程,以便執(zhí)行不同于父進(jìn)程的代碼。子進(jìn)程可能會(huì)通過(guò)這個(gè)返回值執(zhí)行某些特定的初始化工作或處理。

問(wèn)題3:fork兩個(gè)返回值如何分別給父子進(jìn)程返回?

父進(jìn)程:父進(jìn)程使用返回子進(jìn)程的PID,來(lái)管理或等待子進(jìn)程。子進(jìn)程:子進(jìn)程返回0,子進(jìn)程用這個(gè)值來(lái)判斷自己是子進(jìn)程,以執(zhí)行不同于父進(jìn)程的代碼邏輯(比如初始化、執(zhí)行任務(wù)等)。fork返回負(fù)值,表示fork調(diào)用失敗(資源不足等),它會(huì)返回-1,并且沒(méi)有子進(jìn)程創(chuàng)建。操作系統(tǒng)會(huì)設(shè)置errno來(lái)表示具體的錯(cuò)誤原因。2.4 進(jìn)程狀態(tài)請(qǐng)看linux內(nèi)核關(guān)于進(jìn)程狀態(tài)的描述:

R(running): 運(yùn)行狀態(tài),表示某進(jìn)程正在運(yùn)行或準(zhǔn)備運(yùn)行。S(sleep): 睡眠狀態(tài),進(jìn)程在等待某些事件完成(也稱為淺度睡眠,可中斷睡眠)。D(disk sleep): 磁盤休眠狀態(tài),進(jìn)程通常在等待I/O操作完成(也稱為深度睡眠,不可中斷睡眠)。T(stopped): 停止?fàn)顟B(tài),可以通過(guò)發(fā)送信號(hào)讓該進(jìn)程繼續(xù)進(jìn)行。t(Tracing stop): 通常是在進(jìn)行調(diào)試或進(jìn)程跟蹤時(shí)出現(xiàn)的狀態(tài)。X(dead): 死亡狀態(tài),不會(huì)出現(xiàn)在進(jìn)程列表中。Z(Zombie): 僵尸狀態(tài),子進(jìn)程已結(jié)束,父進(jìn)程為獲取子進(jìn)程的退出信息。2.4.1 查看進(jìn)程狀態(tài)使用ps aux 或 ps ajx 命令可以查看進(jìn)程的詳細(xì)狀態(tài)。 命令選項(xiàng)含義:

a:顯示一個(gè)終端所有的進(jìn)程,包括其他用戶的進(jìn)程。x:顯示沒(méi)有控制終端的進(jìn)程,例如后臺(tái)運(yùn)行的守護(hù)進(jìn)程。j:顯示進(jìn)程歸屬的進(jìn)程組ID、會(huì)話ID、父進(jìn)程ID,以及與作業(yè)控制相關(guān)的信息。u:以用戶為中心的格式顯示進(jìn)程信息,提供進(jìn)程的詳細(xì)信息,如用戶、CPU和內(nèi)存使用情況等。僵尸進(jìn)程危害 進(jìn)程的退出狀態(tài)必須被維持下去,因?yàn)樗嬖V關(guān)心它的進(jìn)程(父進(jìn)程),你交給我的任務(wù),我辦得怎么樣了。如果父進(jìn)程一直不讀取,那子進(jìn)程就一直處于Z狀態(tài)。 ? 維護(hù)退出狀態(tài)本身就是要用數(shù)據(jù)維護(hù),也屬于進(jìn)程基本信息,所以保存在task_struct(PCB)中, 換句話說(shuō),Z狀態(tài)一直不退出,PCB一直都要維護(hù)?是的! ? 一個(gè)父進(jìn)程創(chuàng)建了很多子進(jìn)程,就是不回收,是不是就會(huì)造成內(nèi)存資源的浪費(fèi)。因?yàn)?a href="http://m.babyishan.com/tag/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84">數(shù)據(jù)結(jié)構(gòu)對(duì)象本身就要占用內(nèi)存,想想C中定義一個(gè)結(jié)構(gòu)體變量(對(duì)象),是要在內(nèi)存的某個(gè)位置進(jìn)行開辟空間! ? 內(nèi)存泄漏

如果父進(jìn)程先退出,那么子進(jìn)程后退出,進(jìn)入Z狀態(tài)后,該如何處理呢? ? 父進(jìn)程先退出,子進(jìn)程就稱之為“孤兒進(jìn)程” ? 孤兒進(jìn)程被1號(hào)init進(jìn)程領(lǐng)養(yǎng),當(dāng)然要有init進(jìn)程回收

父進(jìn)程等待子進(jìn)程退出(避免子進(jìn)程成為孤兒進(jìn)程)父進(jìn)程可以通過(guò)適當(dāng)?shù)倪M(jìn)程管理確保它會(huì)在子進(jìn)程結(jié)束時(shí)正確地回收子進(jìn)程的資源,避免進(jìn)程成為孤兒進(jìn)程。常用的技術(shù)包括:

wait() 或 waitpid():父進(jìn)程可以使用wait() 或 waitpid() 來(lái)等待子進(jìn)程結(jié)束,并獲取子進(jìn)程的退出狀態(tài),從而清理和回收子進(jìn)程的資源。這樣,即使父進(jìn)程在結(jié)束之前退出,它也能確保子進(jìn)程的資源得到回收。

使用 signal() 或 sigaction() 捕獲終止信號(hào)如果父進(jìn)程結(jié)束時(shí)沒(méi)有來(lái)得及清理子進(jìn)程的資源,可以通過(guò)捕獲特定信號(hào)(如SIGCHLD)來(lái)及時(shí)回收子進(jìn)程的資源。通過(guò)設(shè)置SIGCHLD信號(hào)處理函數(shù),父進(jìn)程可以在子進(jìn)程結(jié)束時(shí)自動(dòng)清理。

避免父進(jìn)程直接退出父進(jìn)程應(yīng)該在子進(jìn)程完成后再退出,例如通過(guò)使用wait()等系統(tǒng)調(diào)用等待子進(jìn)程完成后再退出。如果父進(jìn)程在子進(jìn)程結(jié)束前退出,可能導(dǎo)致子進(jìn)程變成孤兒進(jìn)程。

定期檢查子進(jìn)程狀態(tài),使用waitpid()等方法主動(dòng)回收子進(jìn)程的資源。

三. 最后

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊8 分享