?在講進(jìn)程之前首先就是需要去回顧一下我們之前學(xué)的操作系統(tǒng)是干嘛的,首先操作系統(tǒng)是一個(gè)軟件,它是對(duì)上提供一個(gè)良好高效,穩(wěn)定的環(huán)境的,這是相對(duì)于用戶來(lái)說(shuō)的,對(duì)下是為了進(jìn)行更好的軟硬件管理的,所以操作系統(tǒng)是一個(gè)進(jìn)行軟硬件管理的軟件。
實(shí)際上我們的硬盤(pán),鍵盤(pán)和顯示器這些是我們的硬件,但是操作系統(tǒng)是不能直接對(duì)我們的硬件進(jìn)行控制,所以操作系統(tǒng)和我們的硬件中還有一層就是我們的驅(qū)動(dòng)程序,那還有就是我們的用戶是不能直接對(duì)我們的操作系統(tǒng)進(jìn)行訪問(wèn)的,都會(huì)通過(guò)系統(tǒng)調(diào)用的方式來(lái)對(duì)我們的操作系統(tǒng)進(jìn)行訪問(wèn),這些都是我們來(lái)學(xué)習(xí)今天文章內(nèi)容的前言部分,那下面開(kāi)始我們對(duì)進(jìn)程內(nèi)容的了解。
進(jìn)程的概念
進(jìn)程簡(jiǎn)單點(diǎn)來(lái)了解我們可以就認(rèn)為它就是一個(gè)可執(zhí)行的程序,也就是磁盤(pán)里的文件,然后進(jìn)行運(yùn)行起來(lái),那我們?cè)趯W(xué)C語(yǔ)言的時(shí)候都知道我們的可執(zhí)行文件先是在磁盤(pán)里的,我們運(yùn)行的時(shí)候,是要把磁盤(pán)文件加載到內(nèi)存當(dāng)中的,然后我們的內(nèi)存里存的是這個(gè)可執(zhí)行文件的數(shù)據(jù),也就是代碼加上數(shù)據(jù)。
但是被加載到內(nèi)存當(dāng)中的程序?qū)M(jìn)程的描述是不完整的,下面我來(lái)畫(huà)張圖,也就能方便大家來(lái)了解進(jìn)程了。
先描述再組織
操作系統(tǒng)中里面可能一下子加載了很多的進(jìn)程,就像我們的任務(wù)管理器是一樣的,當(dāng)我們打開(kāi)任務(wù)管理器的時(shí)候我們就不難發(fā)現(xiàn)可以存在很多個(gè)進(jìn)程,所以操作系統(tǒng)里面如果有大量的進(jìn)程也是很正常的。所以講一個(gè)程序加載到內(nèi)存的時(shí)候,不僅僅是要把代碼和數(shù)據(jù)加載到內(nèi)存當(dāng)中,同時(shí)也會(huì)產(chǎn)生一個(gè)結(jié)構(gòu)體我們叫他為PCB(process control block),好像是叫這個(gè)。反正它是一個(gè)結(jié)構(gòu)體,里面存放的是這個(gè)進(jìn)程的屬性加上下一個(gè)PCB結(jié)構(gòu)體的指針,還有就是一個(gè)內(nèi)存指針,指向的就是我們的內(nèi)存里的代碼和數(shù)據(jù)。
看下面的這個(gè)圖
所以操作系統(tǒng)對(duì)進(jìn)程的管理最后就是對(duì)鏈表的增刪查改
最后就是我們講了這么多,進(jìn)程其實(shí)就是??
進(jìn)程 == PCB結(jié)構(gòu)體 + 代碼和數(shù)據(jù)
這里也就是符合我們講的先描述(結(jié)構(gòu)體) 再組織(鏈表)
這里再給大家加個(gè)餐,我們之前說(shuō)操作系統(tǒng)其實(shí)就是一款對(duì)軟硬件進(jìn)行管理的軟件,我們也可以認(rèn)為操作系統(tǒng)再我們電腦開(kāi)機(jī)的時(shí)候也是存放在我們的磁盤(pán)當(dāng)中的,我們認(rèn)為它就是一個(gè)二進(jìn)制的文件。
所以開(kāi)機(jī)的時(shí)候我們發(fā)現(xiàn)我們的電腦不是馬上開(kāi)機(jī)的,而是等待一會(huì)然后進(jìn)行開(kāi)機(jī)的,那么這幾秒的時(shí)間就是把操作系統(tǒng)的這個(gè)軟件的數(shù)據(jù)拷貝到內(nèi)存當(dāng)中去的,然后我們的操作系統(tǒng)就會(huì)根據(jù)我們的進(jìn)程來(lái)進(jìn)行malloc出PCB的結(jié)構(gòu)體,有幾個(gè)進(jìn)程就malloc幾個(gè)PCB出來(lái),最后再進(jìn)行鏈接。
所以操作系統(tǒng)對(duì)進(jìn)程的管理不是對(duì)我們的可執(zhí)行程序進(jìn)行管理,而是對(duì)我們的結(jié)構(gòu)體PCB進(jìn)行管理的
??
系統(tǒng)的接口
操作系統(tǒng)如果是想給我們提供服務(wù)的話,我們用戶是不能直接對(duì)我們的操作系統(tǒng)進(jìn)行訪問(wèn)的,原因呢就是如果我們改動(dòng)我們操作系統(tǒng)中的數(shù)據(jù)和一些數(shù)據(jù)結(jié)構(gòu)的化,我們的操作系統(tǒng)就不能給我們用戶提供很好的服務(wù),就比如操作系統(tǒng)其實(shí)就是我們的銀行,如果我們要去存錢(qián)或者取錢(qián)的時(shí)候,難道銀行是直接把小金庫(kù)暴露給我們嗎,我們是直接用銀行電腦給我們的余額加上5個(gè)0的嗎,那這樣不就亂套了嗎,所以我們?nèi)绻胍L問(wèn)我們的操作系統(tǒng)的時(shí)候,我們就需要利用好我們的系統(tǒng)調(diào)用接口或者標(biāo)準(zhǔn)庫(kù)來(lái)對(duì)我們的操作系統(tǒng)進(jìn)行訪問(wèn),如果我們直接對(duì)操作系統(tǒng)進(jìn)行訪問(wèn)的化就和我們直接去搶銀行是沒(méi)有區(qū)別的。
?
簡(jiǎn)單點(diǎn)我們就可以這樣認(rèn)為這個(gè)是操作系統(tǒng)的內(nèi)核
總結(jié):我們操作系統(tǒng)要運(yùn)行我們的進(jìn)程的時(shí)候,這個(gè)排隊(duì)的過(guò)程就是讓我們的PCB結(jié)構(gòu)體進(jìn)行排隊(duì),而不是內(nèi)存中的代碼和數(shù)據(jù)進(jìn)行排隊(duì)。
?理解一個(gè)概念:什么是動(dòng)態(tài)運(yùn)行?
我么可以理解為PCB在不同的隊(duì)列中,進(jìn)程就可以訪問(wèn)不同的空間。
進(jìn)程的查看
引入話題
在我們考上大學(xué)的時(shí)候,我們的大學(xué)(監(jiān)獄,不想上學(xué))都會(huì)給新生一個(gè)編號(hào)
?也就是我們的學(xué)號(hào),我們每個(gè)人都是有一個(gè)不一樣的學(xué)號(hào),那么進(jìn)程也是這個(gè)樣子的,所以我們需要了解的就是進(jìn)程的標(biāo)識(shí)符我們可以稱(chēng)作為pid。
pid : 在每一個(gè)進(jìn)程中,都會(huì)存在唯一的標(biāo)識(shí)符也就是我pid
我們可用用指令來(lái)查看進(jìn)程的pid
這是一個(gè)Makefile里面寫(xiě)的代碼,還有一個(gè)就是我們.c文件里寫(xiě)的代碼,我們?cè)谖覀兊挠疫呏匦麻_(kāi)一個(gè),方便我們進(jìn)行觀察,這樣我們的代碼就跑起來(lái),這個(gè)時(shí)候就是一個(gè)進(jìn)程在跑,我們?cè)谧筮吙梢詧?zhí)行指令來(lái)進(jìn)行查看。
?ps ajx | head -1 ?&& ps ajx | grep myprocess | grep -v grep
?
?grep -v grep 是不查看該條指令的進(jìn)程,因?yàn)槲覀兊闹噶钇鋵?shí)就是一個(gè)可執(zhí)行的文件,也是一個(gè)進(jìn)程,所以執(zhí)行這個(gè)就可以屏蔽該進(jìn)程。
我們都知道,我們的代碼在進(jìn)行預(yù)處理,編譯,匯編,還有鏈接之后就會(huì)形成可執(zhí)行文件,我們可以用指令開(kāi)查看我們的文件是不是可執(zhí)行文件。
file之和發(fā)現(xiàn)它是一個(gè)可執(zhí)行的文件。
通過(guò)proc目錄來(lái)查看進(jìn)程信息
在 / 下的路徑下有一個(gè)proc,我們也可以在這個(gè)里面來(lái)查看進(jìn)程。
我們上面引進(jìn)的pid就可以用上了,pid是我們進(jìn)程的唯一標(biāo)識(shí)符,認(rèn)識(shí)函數(shù)getpid,通過(guò)man手冊(cè)進(jìn)行查詢
?這是獲取pid的函數(shù),我們上面的指令也可以查看pid
ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep
當(dāng)我們進(jìn)程在跑的時(shí)候,上面的這個(gè)pid也就是我們進(jìn)程的標(biāo)識(shí)符,我們也可以在代碼里獲取pid,來(lái)改寫(xiě)一下代碼。
?這里大家可能是會(huì)有疑問(wèn)的,因?yàn)槲疑厦娴倪M(jìn)程pid已經(jīng)進(jìn)行改變了,這是為什么呢???
因?yàn)槲覀兠看螆?zhí)行我們的代碼的時(shí)候,它就是創(chuàng)建出一個(gè)進(jìn)程,所以pid當(dāng)然是不一樣的。
我們這個(gè)時(shí)候也就可以在proc的目錄下查看一些到底是不是存在這個(gè)進(jìn)程呢。
proc下也是真的有這個(gè)目錄的(哇,真的是你啊(好大聲))?。
我們也可以查看一些他們的屬性,加上 -al就可以來(lái)看看細(xì)節(jié)了。
我們只需要關(guān)注圖中畫(huà)紅的部分就可以了。exe其實(shí)就是可執(zhí)行文件,因?yàn)檫@些文件都是該進(jìn)程下的,我們知道我們的進(jìn)程 == 代碼和數(shù)據(jù) + 內(nèi)核的數(shù)據(jù)結(jié)構(gòu),每個(gè)進(jìn)程都有相對(duì)于的task_struct
也就是我們之前講的PCB,PCB里是有它的屬性的,這個(gè)是我們知道,所以exe相當(dāng)于告知該進(jìn)程對(duì)應(yīng)的磁盤(pán)上哪個(gè)是可執(zhí)行文件,也就是對(duì)應(yīng)的磁盤(pán)文件。
那cwd就是當(dāng)前的工作路徑,這個(gè)和我們的pwd是同一個(gè)路徑。
做個(gè)小實(shí)驗(yàn)
現(xiàn)在我們就來(lái)改改我們的代碼,我們?cè)贑語(yǔ)言的時(shí)候是講過(guò)fopen函數(shù)的時(shí)候,如果我們是以寫(xiě)的方式打開(kāi)的化,沒(méi)有這個(gè)文件的時(shí)候也是會(huì)創(chuàng)建出新的文件出來(lái)的,而且是在當(dāng)前工作路徑下創(chuàng)建的,我們可以來(lái)看看代碼應(yīng)該怎么進(jìn)行修改呢,
?
我們的代碼進(jìn)行這樣子修改后發(fā)現(xiàn)在當(dāng)前的路徑下也是創(chuàng)建出來(lái)新的文件了,所以cwd就是指的當(dāng)前的工作的路徑。
獲取父進(jìn)程的pid
前面也是講過(guò)我們是如何獲得進(jìn)程的pid,但是我們也有辦法來(lái)獲得它的父進(jìn)程的pid在執(zhí)行下面的進(jìn)程的時(shí)候,我們看到的ppid就父進(jìn)程的pid
ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep
那也是有辦法來(lái)查看我們的ppid,就是函數(shù)getppid,用man手冊(cè)進(jìn)行查詢來(lái)看看。
這個(gè)就是我們來(lái)查詢ppid的函數(shù),直接來(lái)嘗試怎么使用。
我們就可以查詢到我們的父進(jìn)程的pid,而且發(fā)現(xiàn)父進(jìn)程每次重新啟動(dòng)的時(shí)候都是不變的,。?
發(fā)現(xiàn)每次的子進(jìn)程的pid是改變了,但是父進(jìn)程的pid是沒(méi)有進(jìn)行改變的
這是為什么呢,我們來(lái)嘗試看看它的父進(jìn)程是怎么個(gè)事。
竟然就是我們的bash進(jìn)程,那我們是不是可以猜測(cè)很多父進(jìn)程的父進(jìn)程他們都是-bash
答案是的?,他們都是-bash的子進(jìn)程
使用fork()函數(shù)創(chuàng)建子進(jìn)程
fork函數(shù)就是專(zhuān)門(mén)創(chuàng)建子進(jìn)程而生的!?。。。?/p>
我們可以用man手冊(cè)進(jìn)行查詢。
FORK(2) Linux Programmer's Manual FORK(2)
NAME
fork - create a child process
SYNOPSIS
#include <unistd.h>
pid_t fork(void);
DESCRIPTION
fork() creates a new process by duplicating the calling process. The new
process, referred to as the child, is an exact duplicate of the calling process,
referred to as the parent, except for the following points:
* The child has its own unique process ID, and this PID does not match the ID of
any existing process group (setpgid(2)).
* The child's parent process ID is the same as the parent's process ID.
* The child does not inherit its parent's memory locks (mlock(2), mlockall(2)).
* Process resource utilizations (getrusage(2)) and CPU time counters (times(2))
are reset to zero in the child.
* The child's set of pending signals is initially empty (sigpending(2)).
* The child does not inherit semaphore adjustments from its parent (semop(2)).
* The child does not inherit record locks from its parent (fcntl(2)).
* The child does not inherit timers from its parent (setitimer(2), alarm(2),
timer_create(2)).
* The child does not inherit outstanding asynchronous I/O operations from its
parent (aio_read(3), aio_write(3)), nor does it inherit any asynchronous I/O
contexts from its parent (see io_setup(2)).
The process attributes in the preceding list are all specified in POSIX.1-2001.
The parent and child also differ with respect to the following Linux-specific
Manual page fork(2) line 1 (press h for help or q to quit)
湊個(gè)子樹(shù)哈哈哈哈哈哈。
我們可以看到引入的頭文件就是unistd這個(gè)頭文件。
我們可以往下看,發(fā)現(xiàn)fork的返回值是有兩個(gè)返回值的,這個(gè)意味著我們有兩個(gè)返回值(好像什么都沒(méi)說(shuō)),我們可以在在代碼里看看它是怎么返回兩個(gè)值的,首先就是他們fork后面創(chuàng)建出子進(jìn)程之和他們的代碼是共享的(包括return0)
我們先寫(xiě)一個(gè)代碼來(lái)看看到底是怎么實(shí)現(xiàn)的,
#include <stdio.h>
2 #include <sys/types.h>
3 #include <unistd.h>
4 //int main()
5 //{
6 // while(1)
7 // {
8 // printf("I am process : pid %d ppid %d\n",getpid(),getppid());
9 // sleep(1);
10 // }
11 //}
12 //
13 //
14 int main()
15 {
16 fork();
17 printf("hello students\n");
18 }
~
我們來(lái)看看效果是怎么樣的呢。
我去,竟然是打印了兩次,那就更能確定一點(diǎn)的就是我們這里是存在連個(gè)進(jìn)程的,不信我們可以使用查看進(jìn)程的指令來(lái)看看,但是因?yàn)檫@個(gè)代碼是一下子就結(jié)束了,那么我們的進(jìn)程也被kill,所以我們是無(wú)法查看的,那在寫(xiě)一個(gè)其他的代碼。
?
代碼
int main()
21 {
22 printf("I am process\n");
23 sleep(3);
24 pid_t p = fork();
25 if(p ==0)
26 {
27 //child
28 while(1)
29 {
30 printf("I am child process pid %d ppid %d\n",getpid(),getppid());
31 sleep(1);
32 }
33 }
34 else
35 {
36
37 while(1)
38 {
39 printf("I am parent process pid %d ppid %d\n",getpid(),getppid());
40 sleep(1);
41 }
42
43 }
44
45
46 }
我們看效果和代碼發(fā)現(xiàn)為什么它能有兩個(gè)返回值,又能進(jìn)行if的語(yǔ)句,也能執(zhí)行fork的語(yǔ)句,如果單單是從語(yǔ)言角度去看的化就不是這個(gè)樣子的,所以我們應(yīng)該是來(lái)看fork函數(shù),fork函數(shù)就是創(chuàng)建子進(jìn)程的,我們可以理解為fork之后的代碼是共享的,因?yàn)槲覀兠總€(gè)函數(shù)包括是main函數(shù)也是有返回值的,所i有有兩個(gè)返回值,那返回值為0的時(shí)候就是child,如果返回值是>0的時(shí)候就是paernt的進(jìn)程,這樣的化就會(huì)產(chǎn)生兩個(gè)進(jìn)程。所以會(huì)產(chǎn)生的進(jìn)程就是兩個(gè)。
那么我們還有個(gè)問(wèn)題就是fork函數(shù)之后,我們的操作系統(tǒng)是做了什么呢。
我們知道進(jìn)程的組成就是task_struct +進(jìn)程的代碼和數(shù)據(jù)
我們可以認(rèn)為子進(jìn)程是繼承了父進(jìn)程的代碼和數(shù)據(jù)的,但是還是要強(qiáng)調(diào)的是我們代碼是繼承的,但是數(shù)據(jù)得獨(dú)立,這樣也就能造成為什么我們的返回值是兩個(gè)的原因。代碼共享就會(huì)導(dǎo)致一定有兩個(gè)返回值。
今天的分享就到這里了。我們下次再見(jiàn)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-841802.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-841802.html
到了這里,關(guān)于進(jìn)程的概念 | PCB | Linux下的task_struct | 父子進(jìn)程和子進(jìn)程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!