系統編程1(進程的概念與原理)

進程的概念與原理

計算機組成部分一般遵循馮諾依曼結構,也就是由控制器、運算器、存儲器、輸入設備、輸出設備五個部分組成。

在這里插入圖片描述
? 程序的編譯

一般在編寫出程序之后,并不能直接運行,而是需要把程序通過編譯器進行編譯,生成可執行文件才能運行。而對于嵌入式學習,一般都是在Linux系統下使用GCC編譯器對程序進行編譯。
在這里插入圖片描述
GCC編譯器是Linux系統默認的C/C++編譯器,大部分Linux發行版本中都是默認安裝的。GCC編譯器主要以Linux命令的形式在shell終端中使用,所以需要大家掌握關于GCC編譯器的相關參數。
在這里插入圖片描述
在這里插入圖片描述
C語言程序編譯過程:源程序 ---- 預處理 — 編譯 — 匯編 — 鏈接 — 可執行文件

預處理:
對源碼進行簡單的加工,GCC編譯器會調用預處理器cpp對程序進行預處理,其實就是解釋源程序中所有的預處理指令,如#include(文件包含)、#define(宏定義)、#if(條件編譯)等以#號開頭的預處理語句。

這些預處理指令將會在預處理階段被解釋掉,如會把被包含的文件拷貝進來,覆蓋掉原來的#include語句,把所有的宏定義展開,所有的條件編譯語句被執行,GCC還會把所有的注釋刪掉,添加必要的調試信息。

預處理指令: gcc -E xxx.c -o xxx.i 會生成預處理文件 xxx.i

編譯:
就是對經過預處理之后的.i文件進行進一步翻譯,也就是對語法、詞法的分析,最終生成對應硬件平臺的匯編文件,具體生成什么平臺的匯編文件取決于編譯器,比如X86平臺使用gcc編譯器,而ARM平臺使用交叉編譯工具arm-linux-gcc。

編譯指令:gcc -S xxx.i -o xxx.s 會生成對應匯編文件 xxx.s

匯編:
GCC編譯器會調用匯編器as將匯編文件翻譯成可重定位文件,其實就是把.s文件的匯編代碼翻譯為相應的指令。

編譯指令:gcc -c xxx.s -o xxx.o 會生成匯編后的文件 xxx.o

鏈接:
經過匯編步驟后生成的.o文件其實是ELF格式的可重定位文件,雖然已經生成了指令流,但是需要重定位函數地址等,所以需要鏈接系統提供的標準C庫和其他的gcc基本庫文件等,并且還要把其他的.o文件一起進行鏈接。-lc -lgcc 是默認的,可以省略

編譯指令:gcc hello.o -o hello -lc -lgcc 會得到可執行文件 xxx // l是lib的縮寫

? 程序的格式

一般對源文件進行編譯和匯編之后,就會得到對應的目標文件xxx.o,目標文件也被稱為可重定位文件,就是指還未完成鏈接的中間文件,用戶可以把這些目標文件制作成在Linux系統下使用的靜態庫libxxx.a或者動態庫libxxx.so。

其實目標文件和可執行文件的內容和結構非常相似,所以Linux系統下把目標文件xxx.o和可執行文件都稱為ELF文件,ELF指的是Executable Linkable Format的縮寫,中文翻譯為可執行可鏈接格式。

注意:可以在linux系統中利用查看文件格式的指令: file 查閱目標文件和可執行文件的區別:

在這里插入圖片描述
思考:還未完成鏈接的目標文件中存儲了哪些內容,以及如何查看目標文件中的內容信息???

回答:目標文件中的內容至少有編譯后的機器指令代碼、數據。除了這些內容以外,目標文件中還包括了鏈接時所需要的一些信息,比如符號表、調試信息、字符串等。一般目標文件將這些信息按不同的屬性,以“節”(Section)的形式存儲,有時候也叫“段”(Segment),一般情況下,它們都表示一個一定長度的區域,基本上不加以區別。

程序源代碼編譯后的機器指令經常被放在代碼段(Code Section)里,代碼段常見的名字有“.code”或“.text”。全局變量和局部靜態變量數據經常放在數據段(Data Section),數據段一般名字都叫“.data”。

注意:linux系統的GCC編譯套件有一款工具叫做objdump,可以查看目標文件內部的數據!
在這里插入圖片描述
數據段中有一個叫做.bss段, bss以前其實是匯編偽指令,作用是為某些數據預留一塊空間,bss其實是Block Started by Symbol,也就是用于存儲未被初始化的全局變量和靜態局部變量,但是在程序編譯階段是沒有分配空間的,在程序運行時會得到空間。

在這里插入圖片描述
在這里插入圖片描述
另外,objdump工具也可以實現把可執行文件進行反匯編,可以把得到的反匯編代碼重定向到某個文本中進行查看 “objdump -D demo > > xxx.txt”

? 進程的概念

當源文件編譯通過并且完成鏈接動作之后,則得到一個可以執行的ELF文件,ELF文件中包含了程序的指令和數據以及相關函數接口的跳轉地址等信息,當用戶運行程序時,操作系統就會把程序相關的指令和數據載入內存,并為程序分配對應的內存空間,然后通知CPU完成程序的相關動作。

用戶編寫的源文件是存儲在外存(磁盤)中的,而使用編譯器生成的ELF可執行文件也是存儲在外存中的,這兩者都是靜態的,操作系統也并沒有為兩者分配系統資源。

在這里插入圖片描述
當可執行文件得到運行,操作系統才會把可執行文件中的指令和數據從外存中讀取出來并寫入內存,并且會為程序分配系統資源(內存空間、CPU使用權等),所以程序從靜態變為動態,這種正在進行中的程序,操作系統就把其稱之為進程(process)。也可以理解為進程是程序在處理器上的一次執行過程。

進程定義:進程是一個具有一定獨立功能的程序在一個數據集合上依次動態執行的過程。進程是一個正在執行程序的實例。

注意:進程是操作系統分配資源的基本單位!操作系統是以進程為單位來分配系統資源的,比如內存空間、CPU使用權等。 線程是操作系統調度資源的最小單位! 進程包含線程!

? 進程的特征

進程具有四個基本特征,分別是動態性、并發性、獨立性、異步性,具體的區別如下所示:

(1) 動態性:進程是程序在處理器上的一次執行過程,因而是動態的。比如進程會在程序運行時被創建出來,當無法獲取足夠的系統資源時進程會暫停,當得到資源后會繼續執行。

(2) 并發性:多個進程同時存在于內存中,目的是與其他程序并發執行,提高資源的利用率。

(3) 獨立性:進程是一個能獨立運行的基本單位,也是系統進行資源分配和調度的獨立單位。

(4) 異步性:指的是進程以各自獨立的、不可預知的速度向前推進。一個進程的執行過程可能是無法被預測的,因為會受到各方面因素的影響,比如當系統資源不夠時或者出現其他進程搶占資源時,都會影響進程的執行進度。

? 進程的組成

思考:操作系統中可能會有n個進程同時執行,請問操作系統如何掌握這些進程的執行情況?

回答:一般進程在創建之后,操作系統都會為進程分配一塊內存來記錄進程的各項參數信息,所以這塊內存被稱為進程控制塊(Processing Control Block,縮寫為PCB)。每個進程都有PCB,用于標識進程的存在以及記錄進程的信息。

在Linux系統中進程控制塊PCB是以一個名稱叫做struct task_struct的結構體作為載體來存儲信息的,該結構體被定義在一個名稱叫做sched.h的頭文件中。

在這里插入圖片描述
進程一般由三個部分組成,分別是進程控制塊、代碼段、數據段。代碼段指的是進程中能被調度程序調度到CPU上執行的程序代碼段,數據段指的是進程對應的程序原始數據或者程序執行過程中產生的中間數據等。

不同操作系統對于一個進程的信息記錄是不同的,也就是PCB中的內容會有一些區別,但是大同小異,基本都會包含以下內容:

  1. 進程標識符

每個進程都有一個有系統分配的唯一的PID進程標識符(process identifier),用于區分系統中的其他進程,這個PID也是Linux內核提供給用戶訪問進程的一個接口,用戶可以通過PID控制進程。

比如Windows系統可以通過任務管理器了解系統中正在執行的進程的數量以及進程的狀態:

在這里插入圖片描述
思考:windows系統下可以通過任務管理器查看進程的PID,那Linux系統如何查看進程PID?

回答:Linux系統中提供了關于獲取進程狀態的shell命令:ps ,該命令的使用方法詳見man手冊,一般使用 ps -ef 或者 ps -aux來查看Linux系統中所有用戶相關的進程的所有信息。

在這里插入圖片描述
2) 進程當前狀態

在進程的運行過程中由于系統中多個進程的并發運行和相互制約的結果,所以使進程的狀態不斷發生變化。操作系統以進程的狀態來作為調度程序分配處理器的依據。

通常一個運行中的進程至少可劃分為5種基本狀態:就緒態、運行態、阻塞態、創建態、結束態。當然進程狀態的叫法是比較靈活的,大家不用死記硬背,重在理解相關概念。

A. 創建態

指的是進程正在被創建,但是還沒有準備好,也就是還沒有達到就緒狀態,此時系統申請進程PCB需要的內存空間,并向PCB中填寫關于進程的管理信息,然后系統分配進程運行需要的資源,最后把進程轉換為就緒狀態。

B. 就緒態

指的是進程已經獲得了除了處理器之外的其他資源,相當于“萬事俱備,只欠東風”,只要進程獲得處理器資源,就可以立即執行。

C.執行態

執行態也被稱為運行態,指的是進程已經獲得了其他資源和處理器資源,并正在被CPU執行的狀態。

D.阻塞態

阻塞態也被稱為暫停態,指的是進程在執行過程中由于某個事件導致無法繼續執行下去,此時進程處于暫時停止的狀態。

E. 結束態

指的是進程正在從系統中消失,原因可能是進程正常退出或者由于其他問題中斷退出運行。有一種情況比較特殊,就是如果該進程退出之后資源還沒有釋放,但是此時進程已經無法被調度和運行,進程就會進入僵尸態,此時用戶需要對這類進程進行處理,避免占用過多資源。

在這里插入圖片描述
思考:Linux系統下運行了n個進程,每個進程的狀態都不同,請問如何區分進程的狀態???

回答:在Linux系統的終端中輸入shell指令: ps -aux,就可以看到當前系統中運行的進程狀態。

在這里插入圖片描述
注意:進程不是一直處于某一個狀態,進程的狀態會受到外界因素和執行進度的影響而發生改變,當然,進程的狀態在某一個時刻是唯一的,也就是在某一時刻進程必須且只能處于一種狀態。

? 進程的控制

進程控制指的是對系統中的所有進程實施有效的管理,其功能一般包括進程的創建、進程的撤銷、進程的阻塞與喚醒等。這些功能一般是由操作系統的內核來實現的。

  1. 進程的創建

Linux系統中的一個進程中可以創建若干個新進程,新創建的進程中又可以創建子進程,所以一般使用進程前趨圖來描述創建的進程之間的關系。進程前趨圖也被稱為進程樹,是為了描述進程家族關系的樹。

在這里插入圖片描述
比如在進程A中創建了一個新進程B,則進程B就是進程A的子進程,進程A就是進程B的父進程。

如果在進程A中創建了2個子進程B和C,進程B中創建了2個子進程D和E,進程C中創建了1個子進程F,則進程A就是該進程家族的祖先。

在Linux系統中運行的所有進程也可以構成一個進程樹,并且該進程樹也有一個祖先,用戶可以通過Linux系統提供的shell命令:pstree 來打印進程關系。
在這里插入圖片描述
可以發現,Linux系統中的所有進程都和一個進程有關系,那就是systemd進程,該進程是Linux系統運行的第一個進程,英文全稱是system daemon,中文翻譯為系統守護進程,系統中其他進程都是該進程的子進程。

守護進程也被翻譯為精靈進程或者后臺進程,是一種旨在運行于相對干凈環境、不受終端影響的、常駐內存的進程,就像神話中的精靈擁有不死的特性,長期穩定提供某種功能或服務。

systemd其實是一個 Linux 系統基礎組件的集合,它提供了一個系統和服務管理器,然后運行為 PID 1的進程,負責在系統啟動或運行時激活系統資源,并且管理服務器進程和其它進程。
在這里插入圖片描述
注意:Linux系統中只有進程才可以在系統運行,所以一個程序想要運行,就必須為該程序創建進程。linux內核提供了一個名字叫做fork()的系統調用接口,該接口可以在進程中創建一個子進程。
在這里插入圖片描述
在這里插入圖片描述
可以看到fork函數的返回值對于父進程和子進程而言是不同的,fork函數在父進程中返回的是創建成功的子進程的PID,fork函數在子進程中的返回值是0,當然,如果子進程失敗則返回-1。

思考:由于子進程會拷貝父進程的代碼段和數據段,所以父進程剩余的程序會執行兩遍,請問如何區分到底是哪個進程在執行程序?是否父進程的程序會優先于子進程執行?

回答:通過fork函數的返回值來區分父進程和子進程,父進程和子進程的執行順序是由操作系統的調度器決定的。也可以選擇利用某些機制來調整執行順序。

在這里插入圖片描述
獲取當前進程PID的函數接口getpid(),獲取當前進程的父進程PID的函數接口是getppid()
在這里插入圖片描述
思考:調用fork函數之后可以創建一個子進程,但是調用了一次fork函數為什么會有兩個不同的返回值?

回答:就是調用fork的時候子進程已經拷貝了父進程的代碼段、數據段、堆棧段,所以fork函數還沒有執行完成,就會在兩個進程空間繼續執行,就會得到兩個不同的返回值。

  1. 進程的撤銷

一個進程在完成自身任務之后應該及時撤銷,這樣就可以及時的釋放進程的資源,此時可以分為兩種情況:一種是撤銷指定進程,另一種是撤銷指定進程以及該進程的所有子孫進程。不管是哪種情況,都應該及時回收進程占用的資源。

Linux系統中提供了一個名稱叫做wait()的系統調用接口,該接口用于讓父進程等待子進程的狀態改變并獲取已經改變狀態的子進程的信息。

在這里插入圖片描述
僵尸態指的是進程終止但是并未釋放相關資源的一種狀態,此時由系統內核對處于僵尸態的進程進行維護,處于僵尸態的進程會占用創建進程的資源和數量,如果僵尸態進程數量太多,則會導致系統無法創建新進程。

所以父進程應該及時的對終止的子進程進行等待,這樣就可以回收子進程占用的資源,當然,如果父進程終止,則處于僵尸態的子進程會由系統內核完成資源的回收。

注意:如果當前進程沒有子進程,則wait函數立即返回,如果當前進程有很多個子進程則wait函數會回收第一個變為僵尸態的子進程資源。

wait函數的參數是一個指針,用于記錄子進程的退出狀態,如果該參數為NULL,則表示當前進程放棄子進程的退出狀態。對于該指針中記錄的值,用戶可以通過系統提供的宏定義來分析子進程的退出狀態。

在這里插入圖片描述
通過man手冊可以發現Linux內核還提供了另一個叫做waitpid()的系統調用函數,該函數也可以等待子進程狀態改變并回收子進程的系統資源,只不過該函數的針對性更強,可以指定回收某個子進程的系統資源。
在這里插入圖片描述
在這里插入圖片描述
3) 進程的執行

思考:既然在一個進程中可以創建多個子進程,并且子進程和父進程的數據段和代碼段是相同的,也就是一份程序會執行兩次,一般情況下是沒有意義和必要的,請問能否讓子進程單獨的加載新的程序的代碼段和數據段,如果可以,應該如何實現?

回答:當然是可以的,Linux系統標準庫中提供了一組函數接口來實現在進程中加載和執行指定的程序。

在這里插入圖片描述
這組接口可以把exec作為前綴,然后以exec后面的字符進行分類,比如l指的是list的縮寫,p指的是path的縮寫,e指的是environment的縮寫,v指的是vector的縮寫。

(1) l : 以列表的方式來組織指定程序的參數
(2) v: 以數組的方式來組織指定程序的參數
(3) e: 執行指定程序前順便設置環境變量
(4) p: 執行程序時可自動搜索環境變量PATH的路徑
在這里插入圖片描述
以 execl(const char *pathname, const char *arg, …) 為例,參數pathname是需要加載的指定程序,而arg則是該程序運行時的命令行參數,命令行參數包括程序名本身,并且全部是字符串,其實和帶參數的main函數通過命令行傳參的流程類似,但是函數的參數列表必須以NULL結束,也就是函數的最后一個參數填NULL即可。

其實,linux系統還提供一個函數,名稱叫做system(),這個函數也可以讓新進程執行shell命令。
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901183.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901183.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901183.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《Vue Router實戰教程》5.嵌套路由

歡迎觀看《Vue Router 實戰(第4版)》視頻課程 嵌套路由 一些應用程序的 UI 由多層嵌套的組件組成。在這種情況下,URL 的片段通常對應于特定的嵌套組件結構,例如: 通過 Vue Router,你可以使用嵌套路由配置…

使用Python解決Logistic方程

引言 在數學和計算機科學中,Logistic 方程是描述人口增長、傳播過程等現象的一種常見模型。它通常用于表示一種有限資源下的增長過程,比如動物種群、疾病傳播等。本文將帶領大家通過 Python 實現 Logistic 方程的求解,幫助你更好地理解這一經典數學模型。 1.什么是 Logist…

《從零搭建Vue3項目實戰》(AI輔助搭建Vue3+ElemntPlus后臺管理項目)零基礎入門系列第十二篇(完結篇):數據統計功能實現

🤟致敬讀者 🟩感謝閱讀🟦笑口常開🟪生日快樂?早點睡覺 📘博主相關 🟧博主信息🟨博客首頁🟫專欄推薦🟥活動信息 文章目錄 《從零搭建Vue3項目實戰》(AI輔助…

研究嵌入式軟件架構時遇到的初始化堆棧溢出問題

文章目錄 2025年4月10日新增分析PC寄存器指針值排查問題map文件設計到的知識點1. **.bss 段(Block Started by Symbol)**2. **.data 段**3. **.text 段**4. **.heap 段**5. **.stack 段**6. **.rodata 段(只讀數據段)**7. **.init…

軟件架構評估兩大法:ATAM 和 SAAM 的對比與實踐

架構權衡分析方法(ATAM)和軟件架構分析方法(SAAM)是軟件架構評估領域中非常重要的兩種方法,以下為你詳細介紹: 一、架構權衡分析方法(ATAM) 1.背景與起源:ATAM 是由卡耐…

Python爬蟲-爬取全球股市漲跌幅和漲跌額數據

前言 本文是該專欄的第52篇,后面會持續分享python爬蟲干貨知識,記得關注。 本文中,筆者將基于Python爬蟲,實現批量采集全球股市行情(亞洲,美洲,歐非,其他等)的各股市“漲跌幅”以及“漲跌額”數據。 具體實現思路和詳細邏輯,筆者將在正文結合完整代碼進行詳細介紹。…

電流互感器的兩相星形接線的建模與仿真

微?“電擊小子程高興的MATLAB小屋”獲取巨額優惠 1.模型簡介 本仿真模型基于MATLAB/Simulink(版本MATLAB 2016Rb)軟件。建議采用matlab2016 Rb及以上版本打開。(若需要其他版本可聯系代為轉換) 2.仿真模型 3.仿真結果 3.1一次…

詳解 kotlin 相對 Java 特有的關鍵字及使用

文章目錄 1. val 和 var2. fun3. when4. is 和 !is5. lateinit6. by7. reified8. companion 本文首發地址:https://h89.cn/archives/366.html 最新更新地址:https://gitee.com/chenjim/chenjimblog Kotlin 在兼容Java的基礎上,引入了許多特有…

國標GB28181視頻平臺EasyCVR如何搭建汽車修理廠遠程視頻網絡監控方案

一、背景分析 近年我國汽車保有量持續攀升,與之相伴的汽車保養維修需求也逐漸提高。隨著社會經濟的發展,消費者對汽車維修服務質量的要求越來越高,這使得汽車維修店的安全防范與人員管理問題面臨著巨大挑戰。 多數汽車維修店分布分散&#…

linux RCU技術

RCU(Read-Copy-Update)是Linux內核中的一種同步機制,用于在多核處理器環境中實現無鎖讀取和延遲更新。Linux RCU(Read-Copy-Update)技術通過一種高效的同步機制來處理并發沖突,確保在多核環境中讀者和寫者對…

【筆記ing】AI大模型-02開發環境搭建

按實驗需求合理選用實例規格,一般:模型開發階段:使用最低算力2U8GB CPU。訓練或推理階段:切換至GPU規格,用完及時關閉算力環境,且切回最低算力規格。 每次實驗結束手動關閉實例。使用ModelArts公有云資源。…

Python——numpy測試題目

題目: 生成一個2行3列隨機整數二維數組a使用Numpy方法對(1)中數組a進行整體求積使用Numpy方法對(1)中數組a進行求每列最大值索引定義一個NumPy一維數組 b,元素為 1 到 10 的整數獲取(4&#x…

系分論文《論面向服務開發方法在設備租賃行業的應用》

系統分析師論文系列 【摘要】 2022年5月,我司承接某工程機械租賃企業"智能租賃運營管理平臺"建設項目,我作為系統分析師主導系統架構設計。該項目需整合8大類2000余臺設備資產,覆蓋全國15個區域運營中心與300家代理商,實…

Unity UI中的Pixels Per Unit

Pixels Per Unit在圖片導入到Unity的時候,將圖片格式設置為Sprite的情況下會出現,其意思是精靈中的多少像素對應世界中的一個單位,默認是100 1. 對于在世界坐標中 在世界坐標中,一般對于Sprite的應用是Sprite Renderer組件 使…

Boost Graph Library (BGL) 介紹與使用示例

Boost Graph Library (BGL) 介紹與使用示例 Boost Graph Library (BGL) 是 Boost 庫中用于圖論計算的模塊,提供了處理圖數據結構的通用接口和多種圖算法實現。 BGL 主要特性 提供多種圖表示方式:鄰接表、鄰接矩陣等包含常用圖算法:DFS、BF…

opencv(C++)操作圖像像素

文章目錄 添加噪點的案例圖像像素值1、訪問圖像屬性2、像素訪問方法 at灰度圖像彩色圖像 3、OpenCV 的向量類型4、 圖像傳遞方式 The cv::Mat_ 類1、作用及優點2、使用 cv::Mat_ 簡化像素訪問 用指針掃描圖像背景算法案例原理1. 圖像數據存儲的基本結構2、行填充(Pa…

Python實現貪吃蛇一

貪吃蛇是一款經典的小游戲,最近嘗試用Python實現它。先做一個基礎版本實現以下目標: 1、做一個按鈕,控制游戲開始 2、按Q鍵退出游戲 3、右上角顯示一個記分牌 4、隨機生成一個食物,蛇吃到食物后長度加一,得10分 5、蛇碰…

《AI大模型應知應會100篇》第13篇:大模型評測標準:如何判斷一個模型的優劣

第13篇:大模型評測標準:如何判斷一個模型的優劣 摘要 近年來,大語言模型(LLMs)在自然語言處理、代碼生成、多模態任務等領域取得了顯著進展。然而,隨著模型數量和規模的增長,如何科學評估這些模…

工會考試重點內容有哪些:核心考點與備考指南

工會考試重點內容總結:核心考點與備考指南 工會考試主要考察考生對工會法律法規、職能職責、實務操作等內容的掌握程度,適用于企事業單位工會干部、社會化工會工作者等崗位的選拔。本文梳理工會考試的核心考點,幫助考生高效備考。 一、工會…

Verilog學習-1.模塊的結構

module aoi(a,b,c,d,f);/*模塊名為aoi,端口列表a、b、c、d、f*/ input a,b,c,d;/*模塊的輸入端口為a,b,c,d*/ output f;;/*模塊的輸出端口為f*/ wire a,b,c,d,f;/*定義信號的數據類型*/ assign f~((a&b)|(~(c&d)));/*邏輯功能描述*/ endmoduleveirlog hdl 程…