
系列文章目錄
文章目錄
- 系列文章目錄
- 前言
- 一、馮諾依曼體系結構
- 二、作業系統
- 1.作業系統的概念
- 2.作業系統的目的
- 3.作業系統的定位
- 4.如何理解管理
- 5.作業系統總結
- 6.系統呼叫和庫函式概念
- 三、行程管理
- 1.基本概念
- 2.描述行程-PCB
- 1.task_struct-PCB的一種
- 2.task_ struct內容分類
- 3.組織行程
- 4.查看行程
- 5.通過系統呼叫獲取行程標示符
- 6.通過系統呼叫創建行程-fork初識
- 7.行程狀態
- 1.Linux內核源代碼
- 2.Linux狀態解讀
- 8.行程狀態查看
- 9.行程狀態轉換
- 總結
前言

一、馮諾依曼體系結構
我們常見的計算機,如筆記本,我們不常見的計算機,如服務器,大部分都遵守馮諾依曼體系,

馮諾依曼的兩個重要思想

截至目前,我們所認識的計算機,都是有一個個的硬體組件組成
- 輸入單元:包括鍵盤, 滑鼠,掃描儀, 寫字板等
- 中央處理器(CPU):含有運算器和控制器等
- 輸出單元:顯示幕,列印機等
- 既是輸入單元也是輸出單元網卡等

關于馮諾依曼,必須強調幾點:
- 這里的存盤器指的是記憶體,
- 不考慮快取情況,這里的CPU能且只能對記憶體進行讀寫,不能訪問外設(輸入或輸出設備),
- 外設(輸入或輸出設備)要輸入或者輸出資料,也只能寫入記憶體或者從記憶體中讀取,
- 一句話,所有設備都只能直接和記憶體打交道,

1.作業系統的概念

任何計算機系統都包含一個基本的程式集合,稱為作業系統(OS),籠統的理解,作業系統包括:
- 內核(行程管理,記憶體管理,檔案管理,驅動管理),
- 其他程式(例如函式庫, shell程式等等),
總結:作業系統=作業系統內核+一堆應用,

2.作業系統的目的
- 與硬體互動,管理所有的軟硬體資源,
- 為用戶程式(應用程式)提供一個良好的執行環境,
總結:作業系統對上,給用戶一個穩定高效的環境,對下管理好軟硬體資源,
3.作業系統的定位
- 在整個計算機軟硬體架構中,作業系統的定位是: 一款純正的“搞管理”的軟體,

4.如何理解管理

- 管理的例子

2. 描述被管理物件

3. 組織被管理物件,


-
用戶部分:自主開發,指令,yum,

-
用戶操作介面部分:庫函式,把系統呼叫的函式再次封裝了一遍,提供出來的函式,

-
system call部分:作業系統為程式員提供的介面,

-
作業系統部分:記憶體管理,行程管理,檔案管理,驅動管理,

-
驅動程式:網卡驅動,硬碟驅動,其他驅動,有多少種硬體就對應對少驅動,
-
硬體部分:網卡,硬碟,其他,

5.作業系統總結
計算機管理硬體
- 描述起來,用struct結構體,
- 組織起來,用鏈表或其他高效的資料結構,
6.系統呼叫和庫函式概念
- 在開發角度,作業系統對外會表現為一個整體,但是會暴露自己的部分介面,供上層開發使用,這部分由作業系統提供的介面,叫做系統呼叫,
- 系統呼叫在使用上,功能比較基礎,對用戶的要求相對也比較高,所以,有心的開發者可以對部分系統呼叫進行適度封裝,從而形成庫,有了庫,就很有利于更上層用戶或者開發者進行二次開發,
三、行程管理
1.基本概念
- 課本概念:程式的一個執行實體,正在執行的程式等

- 內核觀點:擔當分配系統資源(CPU時間,記憶體)的物體,
代碼如下:

區分程式和行程:
- 程式:程式本質就是一個檔案,是靜態的,存盤在磁盤當中,
- 行程:程式運行起來之后,就叫做行程,靜態是動態的,由作業系統管理,

2.描述行程-PCB
- 行程資訊被放在一個叫做行程控制塊的資料結構中,可以理解為行程屬性的集合,
- 課本上稱之為PCB(process control block), Linux作業系統下的PCB是: task_struct,

1.task_struct-PCB的一種
- 在Linux中描述行程的結構體叫做task_struct,
- task_struct是Linux內核的一種資料結構,它會被裝載到RAM(記憶體)里并且包含著行程的資訊,
資料結構叫做雙向鏈表,
2.task_ struct內容分類
- 行程標示符: 描述本行程的唯一標示符,用來區別其他行程,
行程PID:在當前作業系統當中唯一標識一個行程,
ps aux:可以查看當前作業系統中當中的所有行程資訊,

- 行程狀態: 任務狀態,退出代碼,退出信號等,

- 行程優先級: 相對于其他行程的優先級,
- 程式計數器: 程式中即將被執行的下一條指令的地址,

- 記憶體指標: 包括程式代碼和行程相關資料的指標,還有和其他行程共享的記憶體塊的指標,

- 背景關系資料: 行程執行時處理器的暫存器中的資料[休學例子,要加圖CPU,暫存器],

- I/ O狀態資訊: 包括顯示的I/O請求,分配給行程的I/ O設備和被行程使用的檔案串列,

- 記賬資訊: 可能包括處理器時間總和,使用的時鐘數總和,時間限制,記賬號等,

- 其他資訊,
- 程式計數器和背景關系資料,

3.組織行程
- 可以在內核源代碼里找到它,所有運行在系統里的行程都以task_struct鏈表的形式存在內核里,
4.查看行程
- 行程的資訊可以通過 /proc 系統檔案夾查看,

- 大多數行程資訊同樣可以使用top和ps這些用戶級工具來獲取,

代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 while(1)
6 {
7 printf("Hello process1\n");
8 sleep(1);
9 }
10 return 0;
11 }
5.通過系統呼叫獲取行程標示符

代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("pid:%d\n",getpid());
6 printf("ppid:%d\n",getppid());
7 return 0;
8 }
6.通過系統呼叫創建行程-fork初識
- 父子行程代碼共享,資料各自開辟空間,私有一份(采用寫時拷貝),


代碼如下:
#include<stdio.h>
#include<unistd.h>
int main()
{
fork();
printf("hello:pid:%d,ppid:%d",getpid(),getppid());
printf("\n");
return 0;
}


-
父行程先運行還是子行程先運行?

-
子行程創建出來后,代碼從哪里開始運行 ?(重點)

-
運行 man fork 認識fork,


-
如何理解行程創建?

-
fork有為啥兩個回傳值,一個父行程回傳子行程的PID,字行程回傳0,



代碼如下:
#include<stdio.h>
#include<unistd.h>
int main()
{
int ret=fork();
if(ret<0)
{
printf("fork error!\n");
}
else if(ret==0)
{
printf("child ret:%d\n",ret);
}
else
{
printf("parent ret:%d\n",ret);
}
return 0;
}
7 . 我們發現子行程的PPID是父行程的PID,而父行程的PPID是bash,所以bash是所有行程的父行程,

代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int ret=fork();
6 if(ret<0)
7 {
8 printf("fork error!\n");
9 }
10 else if(ret==0)
11 {
12 printf("i am child:%d ret=%d\n",getpid(),ret);
13 }
14 else
15 {
16 printf("i am parent:%d ret=%d\n",getppid(),ret);
17 }
18 return 0;
19 }

這里的子行程的父行程是1號行程不是2594行程是因為子行程在列印的時候, 原先的父行程已經退出了 所以子行程被1號行程所領養了,

7.行程狀態
1.Linux內核源代碼
- 為了弄明白正在運行的行程是什么意思,我們需要知道行程的不同狀態,一個行程可以有幾個狀態(在Linux內核里,行程有時候也叫做任務),
下面的狀態在kernel源代碼里定義:
代碼如下:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
2.Linux狀態解讀
- R運行狀態(running) : 并不意味著行程一定在運行中,它表明行程要么是在運行中要么在運行佇列里,

有時候當我們真正運行一個程式,這個行程明明還在運行,但是我們查看行程狀態資訊時行程處于S+睡眠狀態這是為什么呢?

原因是這個程式代碼中cpu訪問記憶體的效率太高,但是IO設備訪問記憶體的效率太低,導致cpu一直在等待IO設備,所以我們查看行程狀態資訊是S+狀態,
代碼如下:
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1)
{
sleep(1);
printf("Hello Linux!\n");
}
return 0;
}
我們只要去除IO輸出陳述句那么程式就一直處于死回圈,那么行程就是運行狀態了,

代碼如下:
#include<stdio.h>
int main()
{
while(1)
;
return 0;
}
-
S睡眠狀態(sleeping): 意味著行程在等待事件完成(這里的睡眠有時候也叫做可中斷睡眠(interruptible sleep)),
如果行程要硬碟尋找資料,但又由于速度太慢,導致行程進入休眠等待狀態,
而在行程D被記憶體殺掉,就會導致深度休眠成為D狀態,

-
D磁盤休眠狀態(Disk sleep)有時候也叫不可中斷睡眠狀態(uninterruptible sleep),在這個狀態的行程通常會等待IO的結束,
-
T停止狀態(stopped): 可以通過發送 SIGSTOP 信號給行程來停止(T)行程,這個被暫停的行程可以通過發送 SIGCONT 信號讓行程繼續運行,
使用 kill -t查看Linux作業系統的信號串列

我們發現9號信號是KILL殺死行程,19號信號是STOP停止行程,18號信號是CONT行程繼續,

如果我們在想要他換狀態,只需kill -18 行程ID就行,

在這里我們又發現這里的S+又變成了S這又如何解釋,
原因很簡單,+號代表前臺行程,無+號代表后臺行程,且后臺行程必須使用kill -9 行程ID才能殺死,
6 . X死亡狀態(dead):這個狀態只是一個回傳狀態,你不會在任務串列里看到這個狀態

7. t(跟蹤狀態)當行程被gdb除錯的時候,會產生t狀態,


8.行程狀態查看
ps aux 可以查看作業系統中所有的行程資訊,

ps axj可以查看作業系統中子行程的父行程ID,


9.行程狀態轉換

總結
以上就是今天要講的內容,本文僅僅簡單介紹了Linux行程概念的前段部分的使用,而行程提供了大量能使我們快速便捷地處理資料的函式和方法,至于行程概念會在后半部分繼續講解,希望大家多多支持!另外如果上述有任何問題,請懂哥指教,不過沒關系,主要是自己能堅持,更希望有一起學習的同學可以幫我指正,但是如果可以請溫柔一點跟我講,愛與和平是永遠的主題,愛各位了,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286954.html
標籤:其他
