1、程式VS進程

 

程式是存放在磁盤上的一序列代碼和數據的可執行映射,是一個靜止的實體。

 

進程是一個執行中的程式,是動態的實體。

 

2、Linux進程的四大要素
<1>有一段供進程執行的程式,該程式可以被多個進程執行。
<2>:有進程專用的內核空間堆棧。
<3>:進程式控制制快(task_struct:有了這個數據結構,進程才能成為內核調度的一個基本單位接受內核的調度。

 

<4>:獨立的用戶空間

 

進程:有獨立的進程空間

 

線程:只有前三條,沒有第四條。

 

內核線程:完全沒有用戶空間。

 

用戶線程:共用用戶空間。

 

3、Linux進程分類:
<1>:互動式進程:這些進程經常和用戶發生交互,所以花費一些時間等待用戶的操作。當有輸入時,進程必須很快的啟動。通常,要求延遲在50-150毫秒。典型的互動式進程有:主控台命令,文本編輯器,圖形應用程式。
<2>:批處理進程(Batch Process):不需要用戶交互,一般在後台運行。所以不需要非常快的反應,他們經常被調度期限制。典型的批處理進程:編譯器,數據庫搜尋引擎和科學計算。
<3>:實時進程:對調度有非常嚴格的要求,這種類型的進程不能被低優先級進程阻塞,並且在很短的時間內做出反應。典型的實時進程:音視頻應用程式,機器人控制等。
批處理進程可能與I/O或者CPU有關,但是實時進程完全通過Linux的調度演算法識別。
其實互動式進程和批處理進程很難區別。
4:Linux進程優先級
<1>、靜態優先級(priority): 被稱為「靜態」是因為它不隨時間而改變,只能由用戶進行修改。它指明瞭在被迫和其它進程競爭CPU之前該進程所應該被允許的時間片的最大值(20)。

 

每個普通進程都一個靜態優先級,內核為其分配的優先級數為:100(高優先級)-139(低優先級)。數值越大,優先級越低。新創建的進程一般繼承父進程的優先級,但是用戶可以通過給nice()函數傳遞「nice value「或者setpriority()改變優先級。

 

<2>:、動態優先級(counter): counter 即系統為每個進程運行而分配的時間片,Linux 兼用它來表示進程的動態優先級。只要進程擁有CPU,它就隨著時間不斷減小;當它為0 時,標記進程重新調度。它指明瞭在當前時間片中所剩餘的時間量(最初為20)

 

事實上,在進程在調度的時候,調度器只察看動態優先級,其值為100-139。通過下面的公式可以根據靜態優先計算出相應的動態優先級。
Dynamicy priority = max (100, min (static priority - bonus + 5, 139))

 

Bonus:0-10,比5小,降低動態優先級,反之,可以提高動態優先級。Bonus和進程的平均睡眠時間有關。

 

<3>、 實時優先級(rt_priority):值為1000。Linux把實時優先級與counter值相加作為實時進程的優先權值。較高權值的進程總是優先於較低權值的進程,如果一個進程不是實時進程,
其優先權就遠小於1000,所以實時進程總是優先。

 

<4>、Base time quantum:是由靜態優先級決定,當進程耗盡當前Base time quantum,kernel會重新分配一個Base time quantum給它。靜態優先級和Base time quantum的關系為:
(1) 當靜態優先級小於120
Base time quantum(in millisecond)= (140 – static priority) * 20
(2) 當靜態優先級大於等於120
Base time quantum(in millisecond)= (140 – static priority) * 5

 

5、Linux 進程的調度演算法
<1>、時間片輪轉調度演算法(round-robin):SCHED_RR,用於實時進程。系統使每個進程依次地按時間片輪流執行的方式。
<2>、優先權調度演算法:SCHED_NORMAL,用於非實時進程。系統選擇運行隊列中優先級最高的進程運行。Linux 採用搶占式的優級演算法,即系統中當前運行的進程永遠是可運行進程中優先權最高的那個。
<3>、FIFO(先進先出) 調度演算法:SCHED_FIFO,用於實時進程。



 

6、Linux 進程的調度時機schedule()

 

方式:主動式和被動式

 

主動式:在內核中直接調用schedule()

 

current->state=TASK_INTERRUPTIBLE
 
 
TASK_RUNNING

 

被動式:用戶搶占——從系統調用或者中斷處理程式返回用戶空間

 

內核搶占——在不支援內核搶占的系統中,進程一旦運行於內核空間就可以一直運行,直到它主動放棄或者時間片耗盡。

 

在支援內核搶占的系統中,更高優先級的進程可以搶占正在內核空間運行的低優先級進程。
有些特例是不允許搶占的。

 

<1>、內核正在中斷處理

 

<2>、內核正在中斷上下文的Bottom Half處理

 

<3>、進程正持有Spinlock自旋鎖

 

<4>、內核正在執行調度程式schedule()





 

7、代碼分析

 

<1>、2.6 版的內核仍然用 task_struct 來表徵進程,盡管對線程進行了優化,但線程的內核表示仍然與進程相同。隨著調度器的改進,task_struct 的內容也有了改進,互動式進程優先支援、內核搶占支援等新特性,在task_struct 中都有所體現。在 task_struct 中,有的屬性是新增加的,有的屬性的值的含義發生了變化,而有的屬性僅僅是改了一下名字。可稱為進程式控制制塊(TCB),主要包含進程標識符、優先級、堆棧空間、進程狀態

 

task_struct源代碼定義在kernel/include/Linux/sched.h中
struct task_struct {

 

volatile longstate; /* -1 unrunnable, 0 runnable, >0 stopped */

 

structthread_info *thread_info;

 

atomic_tusage;

 

unsigned longflags; /* per process flags, defined below */

 

unsigned longptrace;

 

int lock_depth; /* Lock depth */

 

int prio, static_prio;

 

structlist_headrun_list;

 

prio_array_t *array;
 
unsigned long sleep_avg;

 

long interactive_credit;

 

unsigned long longtimestamp;

 

int activated;

 

unsigned long policy;

 

cpumask_t cpus_allowed;

 

unsigned int time_slice, first_time_slice;

 

structlist_headtasks;

 

/*

 

* ptrace_list/ptrace_children formsthe list of my children

 

* that were stolen by a ptracer.

 

*/

 

structlist_head ptrace_children;

 

structlist_head ptrace_list;

 

structmm_struct *mm, *active_mm;
};



 

<2>、核心結構task_struct中的state

 

進程的狀態仍然用 state 表示

 

#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_STOPPED 4
#define TASK_ZOMBIE 8
#define TASK_DEAD 16


 

2.6新增加了兩種狀態:TRACED、DEAD。

 

新增加的TASK_DEAD指的是已經退出且不需要父進程來回收的進程。TASK_TRACED供調試使用。

 

原有的幾個state:

 

TASK_ZOMBIE一個已經終止的但仍保留有任務的進程(已經死了,戶口未注銷)。

 

TASK_RUNNING就緒態(准確的說你應該是task_runable)

 

TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE不同深度的睡眠態

 

TASK_STOPPED描述一個已經停止的進程,當進程收到一個特殊信號或被時候ptrace系統調用的進程監控,並將監控權交給監控進程。Linux2.4版,內核在創建進程是,為每個進程配兩個連續的物理頁面(8KB)它的頂端(低位址部分)用來存儲進程的task_struct結構(約1KB),剩下的約7KB就是進程的系統空間堆棧,內核可以通過棧寄存器指針ESP快速地方位該進程。

 

<3>thread_info

 

在linux2.6中。這兩個頁面頂端存放的不再是進程的整個task_struct結構,而是task_struct中的thread_info,task_struct的大部分資訊保存在棧外,通過的task指針可以方便地訪問到。

 

thread_info是描述一個描述任務的重要結構體,下面將看到thread_info的數據結構定義(/include/asm-386/thread_.h)

 

struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
unsigned long status; /* thread-synchronous flags */
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */


 

mm_segment_t addr_limit; /* thread address space:
0-0xBFFFFFFF for user-thead
0-0xFFFFFFFF for kernel-thread
*/
struct restart_block restart_block;

 

unsigned long previous_esp; /* ESP of the previous stack in case
of nested (IRQ) stacks
*/
__u8 supervisor_stack[0];
};



 

一些主要的環境資訊如下:

 

task指針指向其對應的任務控制塊

 

preempt_count是用來表示內核能否被搶占的使能成員,如果它大於0.表示內核不能被搶占:如果等於0,則表示內核處於安全狀態(即沒有加鎖),可以搶占。

 

Flags裏面有一個TIF_NEED_RESCHED(調度標志)位,如果此標志位為1.則表示應該盡快啟動調度器。

 

8、調度步驟

 

Schedule()函數工作流程:

 

<1>、清理當前運行中的進程

 

<2>、選擇下一個要運行的進程

 

<3>、設置新進程的運行環境

 

<4>、進程上下文切換
 
 
From:CSDN        
arrow
arrow
    全站熱搜

    戮克 發表在 痞客邦 留言(0) 人氣()