【linux基礎】18、進程管理基礎

一、進程概述

1、文件

文件:是磁盤中的一段被標記的存儲空間,本質上是一段數據流,這個標記叫文件名

    文件名可以引用這段數據

文件存儲格式

     二進制格式:

     文本格式(ASCII碼):    

可執行文件:獨特的ELF格式,前幾個字節標識文件的格式,

程序=指令+數據=算法+數據結構


2、進程

   進程是程序的一個具體實現,同一個程序可以執行多次,每次都可以在內存中開闢獨立的空間來裝載,從而產生多個進程,不同的進程還可以擁有各自獨立的IO接口。 

進程ID(Process ID,PID)號碼被用來標記各個進程

UID,GID和SELinux語境決定進程對文件系統的存取和訪問權限,通常從執行進程的用戶來繼承

每個進程都存在生命週期:從創建開始,到運行結束就是整個進程的一個生命週期,而程序是個靜態的文件.

task struct(任務結構體):Linux內核存儲進程信息的數據結構格式,內核就可以追蹤到進程

task list(任務列表):多個任務的task struct組成的鏈表

每個進程意識不到別的進程的存在,以爲只有自己和內核佔用整個內存

進程的啓動和調度都是內核完成的

線性地址空間(虛擬內存):內核爲每個進程虛擬出一個內存空間,

page frame:內存葉框,

init是所有進程的父進程

父進程通過fork()生成子進程,

線程:是進程的執行流,可以共享資源,線程是線程庫實現的,

linux單內核:沒有專門的線程管理工具,也看成進程,輕量級進程

  

3、進程和線程的區別

進程(process):是程序的具體實現,是已運行程序的副本,進程是程序的基本執行實體,進程本身不是基本運行單位,而是線程的容器

線程(thread):是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。

 1)進程是系統進行資源分配的基本單位,有獨立的內存地址空間線程是CPU調度的基本單位,沒有單獨地址空間,有獨立的棧,局部變量,寄存器, 程序計數器等

 2)創建進程的開銷大,包括創建虛擬地址空間等需要大量系統資源; 創建線程開銷小,基本上只有一個內核對象和一個堆棧。

 3)一個進程無法直接訪問另一個進程的資源;同一進程內的多個線程共享進程的資源。 

 4)進程切換開銷大,線程切換開銷小;進程間通信開銷大,線程間通信開銷小。

 5)線程屬於進程,不能獨立執行。每個進程至少要有一個線程,成爲主線程


4、進程的創建

    當計算機開機的時候,內核(kernel)只建立了一個init進程。Linux kernel並不提供直接建立新進程的系統調用。剩下的所有進程都是init進程通過fork機制建立的。新的進程要通過老的進程複製自身得到,這就是fork,fork是一個系統調用。進程存活於內存中。每個進程都在內存中分配有屬於自己的一片空間 (address space)。當進程fork的時候,Linux在內存中開闢出一片新的內存空間給新的進程,並將老的進程空間中的內容複製到新的空間中,此後兩個進程同時運行。
    當父進程創建子進程時,子進程和父進程使用的是同一段內存空間;一旦子進程需要對該段內存空間的數據進行修改時,就會複製該段內存空間的數據到另外一段內存空間,子進程就指向了該段新的內存空間
這種機制叫CoW(寫時複製),如果子進程不對數據進程修改,跟父進程使用的內存空間都是同一個,但是一旦子進程要修改數據,就複製一份數據到另一塊內存供子進程單獨使用,而從此之後,子進程就一直使用新的內存空間了
進程的終止:子進程完成一定的任務之後,釋放掉自己佔用的資源,然後父進程對子進程進行回收

   老進程成爲新進程的父進程(parent process),而相應的,新進程就是老的進程的子進程(child process)。一個進程除了有一個PID之外,還會有一個PPID(parent PID)來存儲的父進程PID。如果我們循着PPID不斷向上追溯的話,總會發現其源頭是init進程。所以說,所有的進程也構成一個以init爲根的樹狀結構。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[[email protected] ~] # pstree
init─┬─ManagementAgent───2*[{ManagementAgen}]       #centos7把init改成了systemd
      ├─NetworkManager
      ├─VGAuthService
      ├─atd
      ├─auditd───{auditd}
      ├─console-kit-dae───63*[{console-kit-da}]
      ├─crond
      ├─cupsd
      ├─dbus-daemon
      ├─dhclient
      ├─hald─┬─hald-runner─┬─hald-addon-acpi
      │      │             └─hald-addon-inpu
      │      └─{hald}
      ├─master─┬─pickup
      │        └─qmgr
      ├─6*[mingetty]
      ├─modem-manager
      ├─polkitd
      ├─rsyslogd───3*[{rsyslogd}]
      ├─sshd─┬─3*[sshd─── bash ]
      │      └─sshd─── bash ─── bash ───pstree
      ├─ssserver
      ├─udevd───2*[udevd]
      ├─vmtoolsd───{vmtoolsd}
      └─wpa_supplicant


5、CPU的工作機制

CPU的工作機制:

  每臺服務器有很多進程等待CPU來處理,每個進程都必須輪流讓CPU來處理,如果第一個進程一直霸佔着CPU不放,就會導致後面的進程一直無法處理。

CPU是分時的:一個CPU在同一時刻只能執行一個任務,CPU自身的寄存器中存放着正在運行的進程的狀態信息,當該進程分配的時間片內沒有完成任務時,也會被內核調度出去,去執行下一個進程,但是之前沒有完成任務的進程數據不會就此丟失,而是會放到內核指定的一個task struct(任務結構體)來存放進程信息,這就稱爲保存現場,當再一次輪到這個沒有完成的進程到CPU執行時,內核就會再度調回這個保存現場的數據(這就被稱爲恢復現場),來繼續執行,直到完成任務.


6、內存的工作機制

內存的工作機制是分空間的:內存分配方式有點類似磁盤,分成很多塊,但在內存裏不叫塊,而是叫頁框(page frame)用於存儲數據,一般一個page的大小爲4K。分配的頁框可以有多個,且可以不連續。

進程需要用到內存數據的時候,怎麼去找內存中不連續的數據? 

  內核會虛擬一個內存空間面向進程,進程不需要直接與實際的物理存儲的內存打交道,只需與內核虛擬出來的內存打交道,內核虛擬出來的內存的大小,與計算機平臺的位數有關係,內核虛擬出來的內存空間叫做線性地址空間,內核虛擬出來的內存對進程而言是連續,且獨佔的。這樣,進程讀寫內存數據時就認爲自己讀取的是一個連續的地址空間,且是獨佔的,這段虛擬出來的空間中,只有真正被使用的部分,內核纔會在物理內存上分配空間進行存儲

swap分區:爲了防止過多的進程將實際物理內存佔滿導致程序無法運行,從而有了swap交換分區的概念,swap分區實際是用來臨時存放內存中暫時用不到的頁面數據。置換時,通常採用LRU算法(最近最少使用)將最近最少用到的數據暫存在交換分區中,

  不能交換的進程稱爲常駐進程集,能夠被交換的進程稱爲虛擬進程集

一次磁盤IO分爲兩段進行:第一段是將數據從磁盤拿到內存中內核空間,第二段時將內核空間的數據複製一份放到用戶空間

  linux運行中的內核的相關信息是通過/proc僞文件系統輸出的,各進程都有一個以其PID命名的子目錄,每個子目錄中有許多文件存儲了進程的相關狀態信息


7、上下文切換
  在進程運行過程中,進程的運行信息被保存於處理器的寄存器和它的緩存中正在執行的進程加載到寄存器中的數據集被稱爲上下文。爲了切換進程,運行中進程的上下文將會被保存,接下來的運行進程的上下文將被被恢復到寄存器中。進程描述和內核模式堆棧的區域將會用來保存上下文。這個切換被稱爲上下文切換。過多的上下文切換是不受歡迎的,因爲處理器每次都必須清空刷新寄存器和緩存,爲新的進程製造空間。它可能會引起性能問題。


8、中斷處理

  中斷處理是優先級最高的任務之一。中斷通常由I/O設備產生,例如網絡接口卡、鍵盤、磁盤控制器、串行適配器等等。中斷處理器通過一個事件通知內核(例如,鍵盤輸入、以太網幀到達等等)。它讓內核中斷進程的執行,並儘可能快地執行中斷處理,因爲一些設備需要快速的響應。它是系統穩定的關鍵。當一箇中斷信號到達內核,內核必須切換當前的進程到一個新的中斷處理進程。這意味着中斷引起了上下文切換,因此大量的中斷將會引起性能的下降。

  在Linux的實現中,有兩種類型的中斷。硬中斷是由請求響應的設備發出的(磁盤I/O中斷、網絡適配器中斷、鍵盤中斷、鼠標中斷)。軟中斷被用於處理可以延遲的任務(TCP/IP操作,SCSI協議操作等等)。你可以在/proc/interrupts文件中查看硬中斷的相關信息。

在多處理器的環境中,中斷被每一個處理器處理。綁定中斷到單個的物理處理中能提高系統的性能。


二、進程管理

1、進程分類

守護進程:daemon,跟終端無關,由內核在系統引導過程中啓動的進程 

用戶前臺進程:用戶通過終端啓動的進程,跟終端相關,ps查看STAT顯示爲+,終端關閉,進程也將被關閉 

注意:也可把前臺啓動的進程收網後臺,以守護模式運行

cpu密集型

IO密集型


2、進程的狀態

wKioL1hThYKTo4lrAABVA8vMh0A947.png

運行態:running

  當進程正在被CPU執行,或等待運行(已經準備就緒隨時可由調度程序執行),則該進程處於運行態(running).

睡眠態:sleeping

可中斷睡眠:interuptible,認爲自己的任務完成了

  處於這個狀態的進程不會被系統調度,當系統產生了一箇中斷或者釋放了進程正在等待的資源,或者收到一個信號,都可以喚醒進程轉換到就緒態(運行態)。

不可終端睡眠:uninteruptible,被IO阻塞

  與可中斷睡眠轉態類似,但只能被wake_up()函數喚醒才能轉換爲就緒態。

就緒態:runnable

  當系統資源已經可用時,進程就被喚醒而準備進入準備運行狀態

停止態:stopped,不可被調度並運行

  進程收到信號SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU時會轉換爲暫停轉態,向其發送SIGCONT信號可讓其轉換爲可運行狀態。

僵死態:zombie,沒有父進程,不釋放內存

  當進程已經停止運行,但其父進程還沒有詢問其狀態時,該進程處於僵死狀態。


3、進程優先級和nice值

   當我們在執行多個作業時,其實每個作業都會進入到CPU的任務分配中,等待CPU來執行,而CPU會根據每個作業的優先級(priority)來判斷誰比較重要,所以有的作業就會優先執行。

Linux 系統中,每個進程都會擁有一個「優先級(priority)」屬性,利用該屬性,讓CPU判斷哪個作業比較重要,哪個作業會優先執行,這使得系統資源分配得更合適。我們可以使用ps來觀察優先級。

  PRI就是Priority的簡寫,NI是nice的簡寫,它們湊在一起,才產生當前的PRI值。PRI越小,表示該進程「優先級越高」,PRI是由系統動態產生的,不是一直固定的值。NI(nice)則是我們額外提供的一個數值,它可以影響PRI的值,它的關聯性是這樣的:

PRI(new)= RPI(old)+ nice

 

進程調度:通過調整進程的優先級來實現

優先級:0-139  數字越小,優先級越高

實時優先級:0-99,由內核調整的,

靜態優先級:100-139,用戶可通過調整nice值來調整優先級,

進程的nice值:用來手動調整調整進程的優先級    #nice值越大優先級越低

         -20,19

 對應優先級:100,139


進程的默認nice值爲0,優先級爲120

普通用戶只能調大進程的nice值,優先級越低,

調整nice值的方法:

  對於尚未啓用的程序:nice -n N COMMAND

  對於運行中的進程:renice N PID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[[email protected] ~] # ps axo nice,command|grep ping
   ping  192.168.10.10
   grep  ping
   
[[email protected] ~] # nice -n -5 ping 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=128  time =0.422 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=128  time =0.231 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=128  time =0.216 ms
64 bytes from 192.168.10.10: icmp_seq=4 ttl=128  time =0.229 ms
64 bytes from 192.168.10.10: icmp_seq=5 ttl=128  time =0.385 ms  
 
[[email protected] ~] # ps axo pid,nice,command|grep ping
22624  -5  ping  192.168.10.10
22703   0  grep  ping
 
[[email protected] ~] # renice 10 22624
22624: old priority -5, new priority 10
[[email protected] ~] # ps axo pid,nice,command|grep ping
22624  10  ping  192.168.10.10
22780   0  grep  ping

4、進程間通信(IPC)
SIGNAL  信號

kill命令能用於實現向其它進程發送信號 
使用格式:

   kill -SIGNAL 進程名

查看信號:

   kill -l

   man 7 signal

信號表示方式:

(1) 完整名稱,例如SIGINT

(2) 簡寫名稱,例如INT

(3) 數據代稱,例如1,2,9,15

常用信號:

SIGHUP:1    通知進程重讀其配置文件以讓新的配置生效,但不用重新啓動進程;

SIGINT:2    打斷正在運行中的進程,相當於鍵盤組合鍵Ctrl+c

SIGKILL:9   強行中止正在運行中的進程

SIGTERM:15  安全中止正在運行中的進程,kill默認使用的信號

SIGSTOP:19  暫停進程

SIGCONT:18  繼續運行指定進程


kill命令常用命令:

  kill [-SIGNAL] COMMAND

  killall [-SIGNAL] 進程名


pkill

  基於名稱和其他屬性查找或信號處理,常用於踢出用戶

1. 將某個終端的用戶踢出

pkill -kill -t pts/2(終端號) 或 pkill -9 -t pts/2

2. 按用戶名踢出用戶

pkill -kill -U test(用戶名)  #大小u寫都可以


二、作業管理

  作業是shell裏面的一個概念,我們的所有操作都是提交給shell,然後通過shell進行解釋後再執行

區別:進程是一個程序在一個數據集上的一次執行,而作業是用戶提交給系統的一個任務
關係:一個作業通常包括幾個進程,幾個進程共同完成一個任務

一個作業是我們提交給shell的一項任務或者批處理,和操作系統無關。 

進程是具體執行的一個可執行程序,是操作系統調度的對象。


1、作業分類

前臺作業:通過終端啓動,並且在停止之前也會一直佔據終端;

後臺作業:作業啓動之時與終端無關,或者是在前臺啓動,但啓動後轉爲與終端無關模式運行;

非守護進程類的程序,啓動以後都在前臺工作

如何讓作業運行於後臺?

   對於已經啓動並處於運行中的作業:

     Ctrl+z      

     注意: 作業被送往後臺後,默認處於stopped狀態;

  對於尚未啓動的作業:

     COMMAND &   #在後臺運行,但如果進程有輸出的話仍會輸出於標準輸出

注意: 此兩類方式相關作業,仍然與終端相關;這意味着,終端終止,將會導致與此終端相關的所有作業被終止;

   剝離進程與終端的關係: #不會隨終端關閉而終止

     nohup COMMAND &


jobs:

  顯示當前shell 環境中已啓動的作業狀態。

1
2
[[email protected] ~] # jobs
[1]+  Stopped                  nice  -n -5  ping  192.168.10.10

  作業號、作業狀態、命令

  +號是表示默認將被fg調回前臺的作業

  -號是下一個變成+號的作業

  用linux的時候經常會碰到類似這種情形,複製,下載一個很大的文件或編輯一個文件,任務佔據着界面不能做其他操作,這個時候想不暫停或中止任務去做別的操作就可以將正在執行的命令送往後臺去運行。   

作業控制命令:

    fg [[%]job_num]:把指定的作業調回前臺繼續執行;默認將帶+號的作業調回到前臺,

    bg [[%]job_num]:把調往後臺的指定的作業啓動起來,讓其後臺默默運行;但此作業必須支持運行於後臺;

    kill [%job_num]:終止指定的作業;

     

前臺進任務,後臺任務,守護進程的區別參考http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html


















本文轉自xiexiaojun51CTO博客,原文鏈接:http://blog.51cto.com/xiexiaojun/1883179 ,如需轉載請自行聯繫原作者