<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [操作系統] 進程的概念與基礎操作詳解

      在現代操作系統中,**進程(Process)**是一個重要的核心概念。它是操作系統管理資源的基本單位,理解進程的概念以及如何操作它是學習操作系統的基礎。本篇文章將深入講解進程的基本概念、結構和一些典型操作。


      什么是進程?

      前文所提:應用程序從磁盤加載進內存,而操作系統的管理方法是描述 + 組織,所以通過該種管理方法形成的管理對象就是進程。

      從用戶的視角來看,進程是一個程序的運行實例;從操作系統的視角來看,進程是一個擁有資源分配能力的實體。

      進程 = 內核數據結構對象 + 自己的代碼和數據

      在Linux中進程可以看做是PCB(task struct)和自己的代碼和數據組成的。PCB中包含該進程的所有屬性,與代碼以及數據共同組成進程,PCB中存在指向其他進程的指針,通過指針的指向,進程通過雙向鏈表的數據結構來進行鏈接,而進程的管理就是對鏈表的增刪查改。并且每個進程都有獨立的地址空間,以避免相互干擾。

      我們所使用的指令、工具以及自己的程序,運行起來,都是進程!

      進程控制塊(PCB)

      操作系統使用**進程控制塊(Process Control Block, PCB)**來描述和管理進程的所有信息。PCB 是一個重要的數據結構,操作系統通過它來追蹤每個進程的狀態。

      在 Linux 操作系統中,PCB 被實現為一個名為 task_struct 的結構體,其主要內容包括:

      PCB 的主要內容分類

      • 標識符:如進程 ID (PID),用于唯一標識進程。
      • 狀態:包括進程當前的運行狀態(運行、就緒、阻塞等)。
      • 優先級:用于調度時比較不同進程的重要性。(CPU計算的優先級)
      • 程序計數器:存儲下一條將要執行的指令地址。
      • 內存指針:指向進程的代碼段、數據段以及共享內存塊。
      • 上下文數據:包括處理器寄存器中的數據。
      • I/O 狀態信息:描述進程使用的文件和 I/O 設備。
      • 記賬信息:記錄進程使用的資源總量和時間。

      PCB 的組織結構

      在 Linux 內核中,所有進程的 PCB 以鏈表形式組織。通過 task_struct 中的 nextprev 指針,形成一個雙向鏈表,對進程進行遍歷和管理。

      如下圖所示:

      外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

      如何查看進程信息

      在 Linux 系統中,可以通過 /proc 文件系統以及用戶級工具來查看進程信息:

      通過 /proc 文件夾

      • 每個進程在 /proc 中都有一個對應的文件夾,文件夾名稱是該進程的 PID。
      • 數字進程目錄是針對單個進程的詳細信息存儲,字母進程目錄(或文件)是關于系統整體信息的匯總。
      • 例如,要查看 PID 為 1 的進程信息,可以訪問 /proc/1。

      通過命令行工具

      • ps** 命令**:顯示進程的詳細信息。

      bash就是命令行解釋器,每啟動一個XShell就會有一個bash進程啟動,所以輸入的指令等信息都是通過父進程bash處理的,所以當使用命令行啟動多個進程后可以發現它們的父進程(PPID)都是bash。

      • top** 命令**:實時顯示系統運行的進程和資源使用情況。

      通過系統調用獲取進程標識符

      進程id(PID) :**<font style="color:rgb(100,106,115);">getpid();</font>**

      ?進程id(PPID): **<font style="color:rgb(100,106,115);">getppid();</font>**

      sys/types.h包含獲取當前進程ID的函數,比如使用getpid();獲取當前進程的PID:

      進程的cwdexe

      1. 現在將進程啟動。

      1. 通過指令查看進程是否存在。

      grep作為指令也是進程,所以顯示的時候也會顯示grep的進程信息。

      1. 查看進程具體信息。


      /proc/[PID]目錄下的cwdexe是與進程相關的重要符號鏈接,它們分別代表了進程的當前工作目錄和可執行文件路徑。理解這兩個概念對于深入掌握進程的行為和狀態非常有幫助。

      cwd(Current Working Directory)

      • 定義
        • cwd是一個符號鏈接,指向進程的當前工作目錄。當前工作目錄是指進程在執行過程中,其相對路徑的基準目錄。就好比你在終端中切換到某個目錄,然后運行一個程序,這個被切換到的目錄就是程序的當前工作目錄。
        • 例如,假設你在/home/user/projects目錄下啟動了一個名為my_app的程序,那么/proc/[PID]/cwd就會指向/home/user/projects目錄。
        • 使用chdir可以改變cwd的指向路徑。
      • 作用和用途
        • 文件訪問基準:當進程嘗試打開一個相對路徑的文件時,這個相對路徑是相對于cwd來解析的。比如,如果my_app程序嘗試創建data.txt文件,直接使用(./data.txt)而沒有指定絕對路徑,那么系統會直接在/home/user/projects下建立/home/user/projects/data.txt(假設cwd/home/user/projects)。
        • 監控和調試:對于系統管理員和開發者來說,通過查看cwd可以了解進程是在哪個目錄下運行的,這對于調試程序(特別是當程序試圖訪問文件時出現路徑錯誤等問題)和監控進程行為非常有用。例如,如果一個進程試圖訪問一個不存在的文件并報錯,查看cwd可以幫助確定它試圖訪問文件的完整路徑,從而更容易地找到問題所在。

      exe(Executable)

      • 定義
        • exe是一個符號鏈接,指向啟動該進程的可執行文件的路徑。這個可執行文件是進程運行的主體,包含了程序的機器代碼和資源。
        • 例如,如果你使用命令/usr/bin/my_app啟動了一個程序,那么/proc/[PID]/exe就會指向/usr/bin/my_app。
      • 作用和用途
        • 程序識別:通過exe鏈接,你可以清楚地知道是哪個可執行文件啟動了這個進程。這對于系統監控工具來說非常重要,因為它們可以根據可執行文件的路徑來識別和分類進程。例如,在一個包含多個不同版本應用程序的系統中,通過exe可以區分是哪個版本的應用程序正在運行。
        • 安全和審計:在安全審計方面,exe可以幫助確定是否有未經授權的程序在運行。如果發現exe指向一個不熟悉或可疑的路徑,這可能是一個安全風險的信號。此外,它也可以用于追蹤軟件的使用情況,比如統計某個特定可執行文件被啟動的次數等。
        • 重新啟動和分析:對于開發者來說,如果需要重新啟動進程或對進程進行分析(如性能分析),知道exe的路徑是非常有用的??梢灾苯油ㄟ^這個路徑來啟動新的進程實例,或者使用調試工具(如gdb)附加到這個可執行文件上進行分析。

      實際應用示例

      假設你正在運行一個名為example_app的程序,你可以在終端中使用以下命令來查看其cwdexe

      pid=$(pgrep example_app)  # 獲取example_app進程的PID
      ls -l /proc/$pid/cwd      # 查看cwd鏈接
      ls -l /proc/$pid/exe      # 查看exe鏈接
      

      這將輸出類似以下內容:

      lrwxrwxrwx 1 user user 0 Jan  1 12:34 /proc/1234/cwd -> /home/user/projects
      lrwxrwxrwx 1 user user 0 Jan  1 12:34 /proc/1234/exe -> /usr/local/bin/example_app
      

      從這個輸出中,你可以看到example_app進程的當前工作目錄是/home/user/projects,而其可執行文件位于/usr/local/bin/example_app。這些信息對于理解進程的行為和進行系統管理非常關鍵。

      認識fork以及進程的獨立

      進程的創建和管理是操作系統的重要功能。在 Linux 中,創建進程主要通過 fork() 系統調用。

      通過man查看fork():

      • 返回值為pid_t類型
      • 包含在頭文件<unistd.h>

      獲取進程和父進程的標識符

      可以通過以下代碼獲取進程的 PID 和其父進程的 PPID:

      PID:getpid();

      PPID:getppid();

      #include <stdio.h>
      #include <sys/types.h>
      #include <unistd.h>
      
      int main() {
          printf("pid: %d\n", getpid());
          printf("ppid: %d\n", getppid());
          return 0;
      }
      

      如何創建子進程以及父子進程關系的理解

      fork() 是 Linux 中用于創建新進程的函數。

      得到的運行結果如下:

      可以看出,在fork();執行后出現了兩個進程,其中一個進程的pid是fork前的進程的pid,一個是新進程的pid。此時就成功的創建了子進程。但是要如何使用fork()呢?


      首先從fork()函數本身開始理解:

      以下是一個代碼示例。

      printf("父進程開始運行,pid:%d \n", getpid());
      
      pid_t id = fork(); // 父子進程的獨立過程是在調用 fork() 函數時完成,之后父子進程獨立
      
      if(id < 0)
      {
      	perror("fork");
      	return 1;
      }	
      else if(id == 0)
      {
      	// child 
      	while(1)
      	{
      		sleep(1);
      		printf("我是一個子進程!我的pid:%d,我的父進程id:%d\n",getpid(), getppid());
      	}
      }
      else
      {
      	// father
      	while(1)
      	{
      		sleep(1);
      		printf("我是父進程!我的pid:%d,我的父進程id:%d\n",getpid(), getppid());
      	}
      }
      

      運行結果如下:

      fork()執行后創建了子進程,并且同上文所講相同,父進程的父進程是bash進程。

      什么是 fork()

      fork() 是用于創建進程的系統調用。

      • 它會從當前運行的進程(稱為父進程)中復制出一個幾乎完全相同的新進程(稱為子進程)。
      • 父子進程幾乎完全獨立,但共享相同的代碼段
      • 父子進程擁有不同的內存空間,彼此之間不影響。

      fork() 的返回值

      fork() 返回兩個值,因為它在兩個進程中執行,分別是:

      1. 在父進程中,fork() 返回子進程的 PID(進程 ID),這是一個正整數(> 0)。
      2. 在子進程中,fork() 返回 0。
      3. 創建子進程失敗返回-1。
      為什么 **fork()** 有兩個返回值?

      操作系統在執行 fork() 時,會基于當前父進程的狀態,創建一個幾乎完全相同的子進程。

      fork() 會把當前的程序和運行環境復制一份,創建一個新的進程。在fork()函數內,return也是代碼語句,所以也會作為拷貝的代碼,申請新的PCB,拷貝父進程的PCB給子進程。在fork中通過區分父子進程后,通過return返回兩個返回值,兩個返回值都對id進行修改,對變量進行修改,觸發了寫時拷貝,因此系統會進行空間及數據的分配。這就是為什么返回兩個返回值的原因,下文會對該過程進行詳細講解。

      • **父進程調用 ****fork()**,操作系統知道它是父進程,所以返回子進程的 PID,方便父進程管理。
      • **子進程調用 ****fork()**,它的視角是:我是子進程,我沒有子進程,所以返回 0

      注意:

      • fork() 的執行結果是兩套完全獨立的運行環境。
      • fork() 的返回值是區分父進程和子進程的關鍵。

      進程獨立的過程詳解

      父子進程的獨立過程是在調用 **fork()** 函數時完成的。具體地說,當 fork() 被調用時,操作系統會執行以下步驟,從而使父進程和子進程完全獨立:

      進程復制的時機

      • **fork()**** 的調用時刻**:操作系統在執行 fork() 時,會基于當前父進程的狀態,創建一個幾乎完全相同的子進程。

      進程復制的內容

      • 進程控制塊(PCB)
        • 操作系統為子進程分配新的 PCB,記錄子進程的狀態信息(如進程號 PID、父進程號 PPID 等)。
        • 子進程的 PCB 是從父進程的 PCB 復制的,因此子進程最初看起來與父進程完全相同。
      • 地址空間
        • 操作系統復制父進程的內存結構給子進程,形成一份幾乎完全相同的內存空間。這包括:
          • 代碼段:子進程共享父進程的代碼段(只讀)。
          • 數據段:父進程中的全局變量和靜態變量會被復制到子進程。
          • 堆和棧:子進程的堆和棧也被復制,但它們的內存分配是獨立的。
      • 文件描述符
        • 父進程打開的所有文件描述符會被子進程繼承,兩者對同一文件的操作是共享的(文件偏移量同步)。

      父子進程何時獨立?

      一旦 fork() 返回,父子進程開始獨立運行:

      • 子進程的內存空間是父進程的副本,但它與父進程完全分離,修改變量不會相互影響。
      • 子進程和父進程的執行流從 fork() 的返回值處分叉:
        • 父進程繼續運行時,fork() 返回子進程的 PID。
        • 子進程繼續運行時,fork() 返回 0。

      父子進程的獨立性體現在以下幾點:

      1. 內存空間獨立
        • 雖然子進程初始時與父進程的內存內容相同,但它的地址空間是獨立的,修改子進程的內存不會影響父進程。
      2. PID 和資源獨立
        • 子進程有自己的 PID,調度策略也可能不同。
        • 子進程的狀態和運行不會直接影響父進程。
      3. 文件描述符共享但獨立操作
        • 父子進程共享文件描述符,但可以獨立關閉或操作文件。

      獨立的實現機制:寫時復制(Copy-on-Write, COW)

      現代操作系統使用了一種優化機制,叫做 寫時復制(COW),以減少不必要的資源浪費:

      • **fork()** 剛返回時,父子進程共享相同的物理內存頁(只讀),因此復制過程很快。
      • 當父進程或子進程試圖修改內存時
        • 操作系統會為需要修改的部分分配新的物理內存。
        • 修改后的內存空間對父子進程來說是獨立的。

      因此,只有在需要時,內存的獨立性才真正實現,也就是需要對對內存中數據進行修改的時候,但邏輯上,父子進程從 fork() 返回后就已經被視為完全獨立了。

      流程圖

      調用 fork() 后,父子進程的分離流程可以表示如下:

      父進程:
        ret = fork();               // 返回子進程 PID (> 0)
        ------------------------------
       |   父進程邏輯                |
       |   printf("父進程部分");      |
       |   獨立運行,繼續父進程代碼   |
        ------------------------------
      
      子進程:
        ret = fork();               // 返回 0
        ------------------------------
       |   子進程邏輯                |
       |   printf("子進程部分");      |
       |   獨立運行,繼續子進程代碼   |
        ------------------------------
      

      寫時拷貝修改ret內容,進程獨立。

      總結:操作系統完成進程獨立的過程

      • **fork()**** 是操作系統分離父子進程的起點**。
      • 通過資源復制、地址空間分離和調度機制,父子進程實現了完全獨立。
      • 父子進程雖然共享代碼和部分資源,但內存、PID 和運行狀態是互相獨立的,確保了它們可以并發執行,互不干擾。
      • 寫時拷貝:當父子進程嘗試修改共享數據時,操作系統會將數據復制到獨立空間。

      基本的獨立靠的是**struct task_struct(PCB)**獨立。

      當父子進程任何一方進行數據修改的時候觸發寫時拷貝,操作系統就把修改的數據在底層拷貝一份,讓整個目標進程修改這個拷貝,脫離代碼共享,實現完全獨立。

      posted @ 2025-01-17 21:13  DevKevin  閱讀(212)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 国产粉嫩区一区二区三区| 亚洲熟女乱一区二区三区| 国产精品一区二区无线| 国内自拍视频一区二区三区| 午夜福利国产精品小视频| 377P欧洲日本亚洲大胆| 国产精品亚洲精品日韩已满十八小| 亚洲欧美日韩精品成人| 激情综合五月丁香亚洲| 蜜臀91精品国产高清在线| 亚洲精品漫画一二三区| 99国产精品自在自在久久| 亚洲人成网站999久久久综合| 男女一级国产片免费视频| 久热这里有精品免费视频| 日本一区二区三区内射| 深夜福利视频在线播放| 91亚洲国产三上悠亚在线播放| 无码熟妇人妻av影音先锋| 日本一级午夜福利免费区| 成人亚洲性情网站www在线观看| 人妻少妇无码精品专区| 欧美牲交a欧美牲交aⅴ免费| 一区二区三区激情都市| 国产欧美性成人精品午夜| 一区二区亚洲人妻av| 亚洲av首页在线| 国产a在视频线精品视频下载| 国产精品v欧美精品∨日韩| 精品午夜福利短视频一区| 国产精品白浆免费视频| 国产91色在线精品三级| 午夜精品国产自在| 亚洲午夜久久久影院伊人| 亚洲精品专区永久免费区| 免费看黄片一区二区三区| 国产 浪潮av性色四虎| 亚洲av色在线播放一区| 人人入人人爱| 定结县| 国产精品无码无卡在线播放|