Linux系統【一】CPU+MMU+fork函數創建進程

切板中的內容輸出到文件### 進程相關概念
程序:編譯好的二進制文件,在磁盤上,不占用系統資源(不包括磁盤)。(劇本)
進程:占用系統資源,是程序的一次運行。(戲劇)

一個程序可以產生多個進程,一個進程可以調用多個程序

并發:并行執行

單道程序設計:DOS系統
多道程序設計:時鐘中斷

中央處理器CPU

存儲介質:按照容量從大到小:

硬盤->內存->cache(高速緩存)->寄存器

預取器:從cache中取出指令
譯碼器:解析指令
算數邏輯單元(ALU):只會+<<
寄存器堆:ALU操作的寄存器扎堆的地方
然后再將寄存器中的值返回給cache

MMU

MMU位于CPU內部:負責虛擬內存和物理內存之間的映射,設置修改內存訪問的級別(CPU中設置了0-3四個等級,Linux系統中用到0級內核區和3級用戶區)
每產生一個進程產生一個虛擬內存:可用的地址空間
每次最小分配物理內存4K(一個page)
同一個程序的不同進程的kernel區內存映射到同一個空間,但是使用的是不同的PCB

PCB

處于kernel區,進程描述符\進程控制塊,實際上是一個task_struct結構體,里面有很多的成員

  • 進程的id,無符號整數
  • 進程狀態:初狀態、就緒狀態、運行狀態、掛起狀態、終止狀態
  • 進程切換時候需要保存和恢復的一些寄存器
  • 描述虛擬地址空間的信息
  • 描述控制終端的信息
  • 當前進程的工作目錄
  • umask掩碼
  • 文件描述符表
  • 和信號相關的信息
  • 用戶id和組id
  • 會話和進程組
  • 進程可以使用的資源上限ulimit -a

環境變量

Linux系統是多用戶多任務的開源操作系統
用戶操作計算機的時候運行的一些信息通過環境變量進行設置

  • 字符串char * environ[],存儲在用戶區,高于stack的起始位置
  • 統一的存儲格式:名字=值[:值]
  • 值用來描述進程環境信息

shell為例,所使用的環境變量為PATH,在解析命令的時候按照PATH中的內容從前往后逐個目錄進行查找,因此如果希望使用新版本軟件應該把新版本軟件的環境變量向前移動

SHELL 所使用的命令解析器在哪里
HOME 家目錄在哪里
LANG	使用的是什么語言
TERM	所使用的終端類型,圖形界面所使用的一般是xterm,可以顯示漢字,字符界面一般不可以

通過程序打印所有的環境變量:

#include<stdio.h>extern char ** environ;//引入環境變量表int main(void)
{int i;for(int i=0;environ[i]!=NULL;++i){printf("%s\n",environ[i]);}return 0;
}

相關函數

  • getenv
    手冊第三章
  • setenv
  • unsetenv刪除環境變量:即使沒有那個環境變量也會返回成功,只有當參數為已經有的環境變量的非法格式例如:name=才會報錯,例如:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main()
{const char* name="123ABC";char *val;setenv(name,"123",1);printf("%d\n",unsetenv("123ABC=1"));	//-1printf("%d\n",unsetenv("123ABC"));			//0return 0;
}

進程控制

創建進程的方法:

  • 運行可執行程序
  • 通過fork函數創建子進程

fork函數創建子進程

#include<unistd.h>
pid_t fork(void)	

fork兩個成功返回值
如果子進程創建失敗則返回-1,并且將錯誤信息保存在erron中,我們可以使用perror輸出錯誤信息。
如果子進程創建成功則會在父進程中返回子進程的ID,在子進程中返回0

父進程的fork返回子進程ID,子進程的fork返回值為0,通過對返回值的判斷處于哪個進程
可執行文件的父進程是bash

創建單個進程
#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;
}

循環創建N個子進程

如果直接使用循環進行創建,則n層循環會創建2n-1個子進程,這顯然不是我們需要的。
因此我們需要在子進程中直接跳出循環,這樣就不會產生過多的子進程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main(int argc,char* argv[])
{if(argc<2){printf("too few arguments\n");exit(1);}if(argc>2){printf("too few arguments\n");exit(1);}int i,limit=argv[1][0]-'0';printf("begin:\n");for(i=0;i<limit;++i){pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){printf("This is %dth son process,pid = %d \n",i+1,(int)getpid());printf("My father process pid = %d \n",(int)getppid());break;}
}printf("end\n");return 0;
}

在《APUE》中說到如果不加控制的話父進程有98%的可能性獲得CPU的控制權(不過我的電腦上并不是這樣),由內核的調度算法決

getuid

獲取當前進程實際用戶IDuid_t getuid(void);
獲取當前進程有效用戶IDuid_t geteuid(void);

getgid

獲取當前進程實際用戶組IDgid_t getgid(void);
獲取當前進程有效用戶組IDgid_t getegid(void);

進程共享

父子進程相同的:全局變量、.data,.text,棧、共享庫、堆、環境變量、用戶ID、宿主目錄、進程工作目錄、信號處理方式都是相同的
父子進程對于前面的變量的處理:讀時共享寫時復制
如果子進程只對前面的數據進行讀取,則和父進程共享同一個變量,如果對前面的數據進行修改(寫,改變),則復制一份新的,指針的話會制定一個新的地址。
父子進程不同的:進程ID,fork返回值,父進程ID,進程運行時間,鬧鐘(定時器),未決信號集
進程運行時間:子進程的運行時間為父進程fork()調用時間
父子進程共享:

  • 文件描述符
  • mmap建立的映射區(進程間的通信)
    我自己寫了一個測試程序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>int main(int argc,char* argv[])
{int fd=open("test",O_CREAT | O_RDWR | O_TRUNC,0644);pid_t fid=getppid();if(argc<2){printf("too few arguments\n");exit(1);}if(argc>2){printf("too few arguments\n");exit(1);}int i,limit=argv[1][0]-'0';printf("begin:\n");for(i=0;i<limit;++i){pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){break;}}char buffer[100];memset(buffer,0,sizeof(buffer));int sz=sprintf(buffer,"This is %dth son process,pid = %d \n",i+1,(int)getpid());write(fd,buffer,sz);if(getppid()==fid){close(fd);printf("end\n");}return 0;
}

gdb調試

使用gdb調試的時候,gdb只能跟蹤一個進程,可以在fork函數調用之前,通過執行設置gdb調試工具跟蹤父進程或者是跟蹤子進程,默認跟蹤父進程。

  • set follow-fork-mode child命令設置gdb在fork之后跟蹤子進程
  • set follow-fork-mod parent設置跟蹤父進程
  • 注意一定在fork函數調用前設置才有效

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

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

相關文章

Ubuntu卸載軟件

用過使用dpkg軟件管理工具得到所有已經安裝的軟件&#xff0c;如果不清楚軟件的全名可以使用grep命令進行查找 然后再使用sudo apt-get remove --purge 軟件名卸載軟件&#xff08;--purge參數會刪除配置文件&#xff0c;刪的干凈一些&#xff09; 例如&#xff1a;

一個重要且實用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因為筆者之前的文章里面有錯誤&#xff0c;今天發現&#xff0c;立馬做個修改。在下面我的一段關于sigchld信號相對于直接調用wait函數的好處時&#xff0c;我說調用wait函數要一直檢測子進程是否執行完…

數據結構實驗之鏈表七:單鏈表中重復元素的刪除

https://blog.csdn.net/blessingxry/article/details/794455111.知識點&#xff1a;逆序建立鏈表&#xff0b;節點刪除 2.題意&#xff1a;按照數據輸入的相反順序&#xff08;逆位序&#xff09;建立一個單鏈表&#xff0c;并將單鏈表中重復的元素刪除&#xff08;值相同的元素…

Python3函數和代碼復用

函數的定義 def 函數名([參數列表]):注釋函數體注意事項 函數形參不需要聲明類型&#xff0c;可以使用return語句在結束函數執行的同時返回任意類型的值&#xff0c;函數返回值類型與return語句返回表達式i的類型一致 即使該函數不需要接受任何參數&#xff0c;也必須保留一堆…

一文說盡C++賦值運算符重載函數(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;關于C的賦值運算符重載函數(operator)&#xff0c;網絡以及各種教材上都有很多介紹&#xff0c;但可惜的是&#xff0c;內容大多雷同且不全面。面對這一局面&#xff0c;在下在整合各種資源及融入個人理解的基…

Python a和a[:]的區別

簡單來講a[:]是深復制&#xff0c;a是淺復制&#xff0c;相當于賦值a的話是賦值了指針&#xff0c;賦值a[:]相當于復制了a對應的那段空間 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)運行結果&#xff1a; remove操作是移除序列中第一個x元素。…

約瑟夫環(c語言程序完整版)

https://blog.csdn.net/m_hahahaha1994/article/details/51742453約瑟夫環&#xff08;約瑟夫問題&#xff09;是一個數學的應用問題&#xff1a;已知n個人&#xff08;以編號1&#xff0c;2&#xff0c;3…n分別表示&#xff09;圍坐在一張圓桌周圍。從編號為k的人開始報數&am…

Linux系統【二】exec族函數及應用

文件描述符 文件描述符表是一個指針數組&#xff0c;文件描述符是一個整數。 文件描述符表對應的指針是一個結構體&#xff0c;名字為file_struct&#xff0c;里面保存的是已經打開文件的信息 需要注意的是父子進程之間讀時共享&#xff0c;寫時復制的原則是針對物理地址而言…

白話C++系列(27) -- RTTI:運行時類型識別

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—運行時類型識別 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何來體現呢&#xff1f;這就要涉及到typeid和dynamic_cast這兩個知識點了。為了更好的去理解&#xff0c;那么我們就通過一個例子來說明。這個…

使用頭文件的原因和規范

原因 通過頭文件來調用庫功能。在很多場合&#xff0c;源代碼不便&#xff08;或不準&#xff09;向用戶公布&#xff0c;只 要向用戶提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫 功能&#xff0c;而不必關心接口怎么實現的。編譯器會從庫中提取相應…

轉圈踢人問題

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N個人圍一圈依次報數&#xff0c;數到3的倍數的人出列&#xff0c;問當只剩一個人時他原來的位子在哪里&#xff1f; 解答&#xff1a;經典的轉圈踢人問題&#xff0c;好吧專業一點&#xff0c;約瑟夫環問題&#xff0…

Linux系統【三】回收子進程

孤兒進程 父進程先于子進程結束&#xff0c;則子進程成為孤兒進程&#xff0c;子進程的父進程成為init進程&#xff0c;則稱init進程領養孤兒進程。現在好像是用戶進程中的system進程。 僵尸進程 進程終止&#xff0c;父進程不進行回收&#xff0c;自己成殘留資源(PCB)存放在…

string類的基本實現

https://blog.csdn.net/qq_29503203/article/details/52265829在面試中面試官常常會讓你寫出string類的基本操作&#xff0c;比如&#xff1a;構造函數&#xff0c;析構函數&#xff0c;拷貝構造等等.下面是除此之外的一些操作&#xff0c;希望可以幫助你更好的理解string以便以…

Python3常用數據結構

Python3中有三種組合數據類型&#xff0c;分別為&#xff1a; 序列類型&#xff1a;字符串&#xff08;str&#xff09;、元組&#xff08;tuple&#xff09;、列表&#xff08;list&#xff09;集合類型&#xff1a;集合&#xff08;set&#xff09;映射類型&#xff1a;字典…

Linux C++ 回射服務器

http://blog.csdn.net/qq_25425023/article/details/53914820回射服務器就是服務端將客戶端的數據發送回去。我實現的回射服務器返回增加了時間。服務端代碼&#xff0c;可以很容易看懂&#xff1a;[cpp] view plaincopy#include <sys/socket.h> #include <stdio.h&g…

TCP第四次揮手為什么要等待2MSL

當客戶端進入TIME-WAIT狀態的時候(也就是第四次揮手的時候)&#xff0c;必須經過時間計數器設置的時間2MSL(最長報文段壽命)后&#xff0c;才能進入關閉狀態&#xff0c;這時為什么呢&#xff1f;&#xff1f;&#xff1f; 這最主要是因為兩個理由&#xff1a; 1、為了保證客戶…

計算機網絡【一】概述+OSI參考模型

網絡概述 局域網:覆蓋范圍小(100m以內)&#xff0c;自己花錢買設備&#xff0c;帶寬固定(10M,100M,1000M)&#xff0c;自己維護&#xff08;接入層交換機直接連接電腦、匯聚層交換機直接連接接入層交換機&#xff09; 廣域網:距離遠&#xff0c;花錢買服務&#xff0c;租帶寬&…

單鏈表逆序的多種方式

https://www.cnblogs.com/eniac12/p/4860642.htmltemplate<class T> void List<T>::Inverse() {if(first NULL) return;LinkNode<T> *p, *prev, *latter; p first->link;   // 當前結點prev NULL;   // 前一結點l…

Linux系統【四】進程間通信-管道

進程間通信&#xff08;IPC Interprocess Communication&#xff09; 進程和進程之間的通信只能通過內核&#xff0c;在內核中提供一塊緩沖區進行通信。內核提供的這種機制叫做IPC 在進程間完成數據傳輸需要借助操作系統提供的特殊方法&#xff0c;如&#xff1a;文件&#xf…

單鏈表各種操作詳解

#include "stdio.h" #include "stdlib.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 20 /* 存儲空間初始分配量 */typedef int Status;/* Status是函數的類型,其值是函數結果狀態代碼&#xff0c;如OK等 */ typedef int…