Linux系统【一】CPU+MMU+fork函数创建进程
切板中的內(nèi)容輸出到文件### 進程相關(guān)概念
程序:編譯好的二進制文件,在磁盤上,不占用系統(tǒng)資源(不包括磁盤)。(劇本)
進程:占用系統(tǒng)資源,是程序的一次運行。(戲劇)
一個程序可以產(chǎn)生多個進程,一個進程可以調(diào)用多個程序
并發(fā):并行執(zhí)行
單道程序設計:DOS系統(tǒng)
多道程序設計:時鐘中斷
中央處理器CPU
存儲介質(zhì):按照容量從大到小:
硬盤->內(nèi)存->cache(高速緩存)->寄存器
預取器:從cache中取出指令
譯碼器:解析指令
算數(shù)邏輯單元(ALU):只會+和<<
寄存器堆:ALU操作的寄存器扎堆的地方
然后再將寄存器中的值返回給cache
MMU
MMU位于CPU內(nèi)部:負責虛擬內(nèi)存和物理內(nèi)存之間的映射,設置修改內(nèi)存訪問的級別(CPU中設置了0-3四個等級,Linux系統(tǒng)中用到0級內(nèi)核區(qū)和3級用戶區(qū))
每產(chǎn)生一個進程產(chǎn)生一個虛擬內(nèi)存:可用的地址空間
每次最小分配物理內(nèi)存4K(一個page)
同一個程序的不同進程的kernel區(qū)內(nèi)存映射到同一個空間,但是使用的是不同的PCB
PCB
處于kernel區(qū),進程描述符\進程控制塊,實際上是一個task_struct結(jié)構(gòu)體,里面有很多的成員
- 進程的id,無符號整數(shù)
- 進程狀態(tài):初狀態(tài)、就緒狀態(tài)、運行狀態(tài)、掛起狀態(tài)、終止狀態(tài)
- 進程切換時候需要保存和恢復的一些寄存器
- 描述虛擬地址空間的信息
- 描述控制終端的信息
- 當前進程的工作目錄
- umask掩碼
- 文件描述符表
- 和信號相關(guān)的信息
- 用戶id和組id
- 會話和進程組
- 進程可以使用的資源上限ulimit -a
環(huán)境變量
Linux系統(tǒng)是多用戶多任務的開源操作系統(tǒng)
用戶操作計算機的時候運行的一些信息通過環(huán)境變量進行設置
- 字符串char * environ[],存儲在用戶區(qū),高于stack的起始位置
- 統(tǒng)一的存儲格式:名字=值[:值]
- 值用來描述進程環(huán)境信息
以shell為例,所使用的環(huán)境變量為PATH,在解析命令的時候按照PATH中的內(nèi)容從前往后逐個目錄進行查找,因此如果希望使用新版本軟件應該把新版本軟件的環(huán)境變量向前移動
SHELL 所使用的命令解析器在哪里 HOME 家目錄在哪里 LANG 使用的是什么語言 TERM 所使用的終端類型,圖形界面所使用的一般是xterm,可以顯示漢字,字符界面一般不可以通過程序打印所有的環(huán)境變量:
#include<stdio.h>extern char ** environ;//引入環(huán)境變量表int main(void) {int i;for(int i=0;environ[i]!=NULL;++i){printf("%s\n",environ[i]);}return 0; }相關(guān)函數(shù)
- getenv
手冊第三章 - setenv
- unsetenv刪除環(huán)境變量:即使沒有那個環(huán)境變量也會返回成功,只有當參數(shù)為已經(jīng)有的環(huán)境變量的非法格式例如:name=才會報錯,例如:
進程控制
創(chuàng)建進程的方法:
- 運行可執(zhí)行程序
- 通過fork函數(shù)創(chuàng)建子進程
fork函數(shù)創(chuàng)建子進程
#include<unistd.h> pid_t fork(void)fork有兩個成功返回值
如果子進程創(chuàng)建失敗則返回-1,并且將錯誤信息保存在erron中,我們可以使用perror輸出錯誤信息。
如果子進程創(chuàng)建成功則會在父進程中返回子進程的ID,在子進程中返回0
父進程的fork返回子進程ID,子進程的fork返回值為0,通過對返回值的判斷處于哪個進程
可執(zhí)行文件的父進程是bash
創(chuàng)建單個進程
#include<stdio.h> #include<stdlib.h> #include<unistd.h>int main() {printf("begin:\n");pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){printf("This is son process,pid = %d \n",(int)getpid());printf("My father process pid = %d \n",(int)getppid());}else{printf("This is father process,pid = %d \n",(int)getpid());printf("My father process pid = %d \n",(int)getppid());sleep(1);}printf("end\n");return 0; }循環(huán)創(chuàng)建N個子進程
如果直接使用循環(huán)進行創(chuàng)建,則n層循環(huán)會創(chuàng)建2n-1個子進程,這顯然不是我們需要的。
因此我們需要在子進程中直接跳出循環(huán),這樣就不會產(chǎn)生過多的子進程
在《APUE》中說到如果不加控制的話父進程有98%的可能性獲得CPU的控制權(quán)(不過我的電腦上并不是這樣),由內(nèi)核的調(diào)度算法決定
getuid
獲取當前進程實際用戶IDuid_t getuid(void);
獲取當前進程有效用戶IDuid_t geteuid(void);
getgid
獲取當前進程實際用戶組IDgid_t getgid(void);
獲取當前進程有效用戶組IDgid_t getegid(void);
進程共享
父子進程相同的:全局變量、.data,.text,棧、共享庫、堆、環(huán)境變量、用戶ID、宿主目錄、進程工作目錄、信號處理方式都是相同的
父子進程對于前面的變量的處理:讀時共享寫時復制
如果子進程只對前面的數(shù)據(jù)進行讀取,則和父進程共享同一個變量,如果對前面的數(shù)據(jù)進行修改(寫,改變),則復制一份新的,指針的話會制定一個新的地址。
父子進程不同的:進程ID,fork返回值,父進程ID,進程運行時間,鬧鐘(定時器),未決信號集
進程運行時間:子進程的運行時間為父進程fork()調(diào)用時間
父子進程共享:
- 文件描述符
- mmap建立的映射區(qū)(進程間的通信)
我自己寫了一個測試程序
gdb調(diào)試
使用gdb調(diào)試的時候,gdb只能跟蹤一個進程,可以在fork函數(shù)調(diào)用之前,通過執(zhí)行設置gdb調(diào)試工具跟蹤父進程或者是跟蹤子進程,默認跟蹤父進程。
- set follow-fork-mode child命令設置gdb在fork之后跟蹤子進程
- set follow-fork-mod parent設置跟蹤父進程
- 注意一定在fork函數(shù)調(diào)用前設置才有效
總結(jié)
以上是生活随笔為你收集整理的Linux系统【一】CPU+MMU+fork函数创建进程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再爱我一次剧情介绍
- 下一篇: Python3函数和代码复用