Linux 进程概念
【基本概念】
?
1.程序(procedure):是執行一系列有邏輯、有順序結構的指令,幫我們達成某個結果。
2.進程(process):是程序在一個數據集合上的一次執行過程,在早期的UNIX、Linux 2.4及更早的版本中,它是系統進行資源分配和調度的獨立基本單位。
3.線程(thread):是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發多個線程,每條線程并行執行不同的任務。因為線程中幾乎不包含系統資源,所以執行更快、更有效率。
?
隨著程序的發展越做越大,又會繼續細分,從而引入了線程的概念,當代多數操作系統、Linux 2.6及更新的版本中,進程本身不是基本運行單位,而是線程的容器。
簡而言之,程序是為了完成某種任務而設計的軟件,而進程就是運行中的程序,一個程序至少有一個進程,一個進程至少有一個線程。線程的劃分尺度小于進程,使得多線程程序的并發性高。另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。
【并行性與并發性】
?
1.并行性(parallelism):指在同一時刻或是同一時間間隔內完成兩種或兩種以上性質相同或不相同的工作,嚴格來講,只要時間上互相重疊,就存在并行性。
2.同時性(smultaneity):指兩個或多個事件在同一時刻發生的并行性。
3.并發性(concurrency):兩個或多個事件在同一時間間隔內發生的并行性。
并行性是并發性的一個特例,并行的事件或活動一定是并發的,反之并發的事件或者活動未必就是并行的。
【進程的特性】
程序只是一些列指令的集合,是一個靜止的實體,而進程不同,進程有以下的特性:
1.動態性:進程的實質是一次程序執行的過程,有創建、撤銷等狀態的變化。而程序是一個靜態的實體。
2.并發性:進程可以做到在一個時間段內,有多個程序在運行中。程序只是靜態的實體,所以不存在并發性。
3.獨立性:進程可以獨立分配資源,獨立接受調度,獨立地運行。
4.異步性:進程以不可預知的速度向前推進。
5.結構性:進程擁有代碼段、數據段、PCB(進程控制塊,進程存在的唯一標志)。也正是因為有結構性,進程才可以做到獨立地運行。
【進程的分類】
?
進程可以從兩個角度來分:以進程的功能與服務的對象來分;以應用程序的服務類型來分;
1)以進程的功能與服務的對象來分
① 用戶進程:通過執行用戶程序、應用程序或稱之為內核之外的系統程序而產生的進程,此類進程可以在用戶的控制下運行或關閉。
② 系統進程:通過執行系統內核程序而產生的進程,該類進程的運行不受用戶的干預,即使是 root 用戶也不能干預系統進程的運行,例如:可執行內存資源分配和進程切換等相對底層的工作。
?
2)以應用程序的服務類型來分
① 交互進程:由一個 shell 終端啟動的進程,在執行過程中,需要與用戶進行交互操作,可以運行于前臺,也可以運行在后臺。
② 批處理進程:是一個進程集合,負責按順序啟動其他的進程。
③ 守護進程:是一直運行的一種進程,在 Linux 系統啟動時啟動,在系統關閉時終止。它們獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。例如:httpd 進程,一直處于運行狀態,等待用戶的訪問;cron 進程,為 crontab 的守護進程,可以周期性的執行用戶設定的某些任務。
【進程的衍生】
?
1.概述
?
啟動了終端,就是啟動了一個 bash 進程,我們可以在 bash 中再輸入 bash 則會再啟動一個 bash 的進程,此時第二個 bash 進程就是由第一個 bash 進程創建出來的。
我們一般稱呼第一個 bash 進程是第二 bash 進程的父進程,第二 bash 進程是第一個 bash 進程的子進程。
2.子進程的由來
關于父進程與子進程便會提及 fork() 與 exec() 這兩個系統調用(system call)。
1)fork() 的作用就是為當前的進程創建一個新的進程,這個新的進程就是它的子進程,這個子進程除了父進程的返回值和 PID 以外其他的都一模一樣,如:進程的執行代碼段,內存信息,文件描述,寄存器狀態等。
2)exec() 的作用是切換子進程中的執行程序,也就是替換其從父進程復制過來的代碼段與數據段。
子進程就是父進程通過系統調用 fork() 而產生的復制品,fork() 就是把父進程的 PCB 等進程的數據結構信息直接復制過來,只是修改了 PID,只有在執行 exec() 之后才會不同。
注:
①?早先的 fork() 比較消耗資源,后來進化成 vfork(),效率提高不少。
?
②?子進程產生的簡單的實現邏輯
pid_t p; p = fork(); if (p == (pid_t) -1)/* ERROR */ else if (p == 0)/* CHILD */ else/* PARENT */3)子進程的退出與資源的回收
子進程是通過父進程而衍生出來的,當一個子進程要正常的終止運行時,或者該進程結束時它的主函數 main() 會執行 exit(n) 或 return n,這里的返回值 n 是一個信號,系統會把這個信號傳給其父進程。
3.僵尸進程與孤兒進程
正常情況下,父進程會收到兩個返回值:exit code(SIGCHLD 信號)與 reason for termination 。之后,父進程會使用 wait(&status) 系統調用以獲取子進程的退出狀態,然后內核就可以從內存中釋放已結束的子進程的 PCB。
由于 PCB 是進程存在的唯一標志,里面存儲著進程的 PID 等消息,因此如若父進程沒有釋放子進程的 PCB ,那么子進程的 PCB 就會一直駐留在內存中,一直留在系統中成為僵尸進程(Zombie)。
簡單來說,僵尸進程與孤兒進程就是:
1)僵尸進程:進程的進程控制塊(PCB)仍駐留在內存中,進程還存在,沒有消亡。
?
2)孤兒進程:父進程非正常的結束,未能及時收回子進程,子進程仍在運行。
僵尸進程是已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其父進程收集,從而釋放它。
但是 Linux 系統中能使用的 PID 是有限的,如果系統中存在有大量的僵尸進程,系統將會因為沒有可用的 PID 從而導致不能產生新的進程。
在 Linux 系統中,孤兒進程一般會被 init 進程所“收養”,成為 init 的子進程。由 init 來做善后處理,所以它并不至于像僵尸進程那樣無人問津,不管不顧,大量存在會有危害。
4.init 進程
進程 0 是系統引導時創建(內核初始化)的一個特殊進程,其最后一個動作就是調用 fork() 創建出一個子進程運行 /sbin/init 可執行文件,該子進程就是 PID=1 的進程 1(init 進程),而進程 0 就轉為交換進程(空閑進程)。
進程 1 是第一個用戶態的進程,再由它不斷調用 fork() 來創建系統里其他的進程,所以它是所有進程的父進程或者祖先進程,同時它是一個守護程序,直到計算機關機才會停止。
通過命令?pstree?可以看到如下結構
通過上圖,我們可以看出 init 進程為所有進程的祖先進程,跟容易看出所有進程的父子關系。
【進程組與會話】
1.進程組(process group)
每一個進程都是一個進程組的成員,而且這個進程組是唯一存在的,他們是依靠 PGID(process group ID)來區別的,而每當一個進程被創建的時候,它便會成為其父進程所在組中的一員。
一般情況,進程組的 PGID 等同于進程組的第一個成員的 PID,并且這樣的進程稱為該進程組的領導者,也就是領導進程,進程一般通過使用 getpgrp() 系統調用來尋找其所在組的 PGID,領導進程可以先終結,此時進程組依然存在,并持有相同的PGID,直到進程組中最后一個進程終結。
2.會話(Session)
?
會話是一到多個進程組的集合,其主要是針對一個虛擬控制臺(tty)建立的,與進程組類似,每當一個進程被創建的時候,它便會成為其父進程所在會話中的一員,每一個進程組都會在一個會話中,并且這個會話是唯一存在的。
會話中的每個進程都稱為一個工作(job),每個會話可以連接一個終端(control terminal),當控制終端有輸入輸出時,都會傳遞給該會話的前臺進程組。
會話意義在于將多個工作囊括在一個終端,并取其中的一個工作作為前臺,來直接接收該終端的輸入輸出以及終端信號,而其他的工作在后臺運行。
通過下圖,可以更加直觀的看出進程組與會話的聯系
注:
1)前臺(foreground):在終端中運行,能與用戶有交互的進程。
2)后臺(background):就是在終端中運行,但是用戶并不能與其任何的交互,也不會顯示其執行的過程。
【工作管理】
?
1.說明:bash(Bourne-Again shell)支持工作控制(job control),而 sh(Bourne shell)并不支持,并且每個終端或者說 bash 只能管理當前終端中的 job,不能管理其他終端中的 job。
2.通過符號 & ,可以讓命令在后臺中運行
上圖中所顯示的 [1] 4813分別是該工作的工作號與該進程的 PID,而最后一行的 Done 表示該命令已經在后臺執行完畢。
3.通過 ctrl + z 使當前工作停止放到后臺
4.通過 jobs 命令可以查看放置在后臺的工作
?
其中第一列顯示的是被放置后臺工作的編號;第二列的 + 表示最近最后被放置后臺的工作,同時也表示預設的工作(若是針對后臺工作的操作,首先會針對預設的工作), - 表示倒數第二被放置后臺的工作,倒數第三個及以后都不會有這樣的符號修飾;第三列表示它們的狀態;最后一列表示該進程執行的命令。
5.通過 fg 命令將后臺的工作拿到前臺
1)命令格式:fg [%工作編號]
?
2)說明:fg后不加參數提取預設工作,加參數提取指定工作的編號。
3)實例:
?
6.通過命令 bg,讓后臺已停止的工作在后臺中運行
1)命令格式:bg [%工作編號]
2)說明:bg 后不加參數提取預設工作,加參數提取指定工作的編號。
3)實例:
7.使用 kill 命令刪除或重啟后臺工作
1)命令格式:kill [-信號值] %工作號
注:
① 不加信號值時,默認為終止。
②?若是使用 kill+信號值 + pid,將會對 pid 對應的進程進行操作;若是使用 kill + 信號值 + %工作號,將會對后臺工作隊應的工作號進行操作。
③ kill 命令的信號值從 1-64,具體作用可以通過 kill -l 查看
2)常用信號值
?
| -1 | 重新讀取參數運行 |
| -2 | 如同 ctrl+c 的操作退出 |
| -9 | 強制終止任務 |
| -15 | 正常的方式終止任務 |
3)實例
總結
以上是生活随笔為你收集整理的Linux 进程概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基础算法 —— 高精度计算 —— 高精度
- 下一篇: linux 其他常用命令