【Linux系统编程】进程概念
1.进程是什么进程也叫做任务task我们这里给出的定义是进程 内核的数据结构struct task_struct 代码和数据。这是一个动态的过程因为数据结构是动态的加载程序到内存的过程叫做创建进程。也就是说所有的指令执行、工具执行、软件执行都是进程。2.怎么理解进程OS内部可以同时存在多个进程 -- OS必然要对进程做管理 -- 先描述再组织描述课本上称之为PCBprocess control blockLinux下的PCB是task_struct{ }Linux中描述进程的结构体叫task_struct它被装载到内存里面并且包含着进程信息属性。组织用数据结构来管理这里我们可以理解为用链表链接起来这里的链表是双链表。这样一来操作系统对进程的管理就转变成了对链表的增删查改3.PCB内部属性内容分类标示符: 描述本进程的唯⼀标示符用来区别其他进程。优先级: 相对于其他进程的优先级。程序计数器: 程序中即将被执行的下⼀条指令的地址。内存指针: 包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针上下文数据: 进程执行时处理器的寄存器中的数据[休学例⼦要加图CPU寄存器]。I/O状态信息: 包括显示的I/O请求,分配给进程的I∕O设备和被进程使用的文件列表。记账信息: 可能包括处理器时间总和使用的时钟数总和时间限制记账号等。其他信息具体详细信息后续会介绍要谈某个进程的属性就先要确定这个进程是哪一个所以每个进程都有唯一特别的id叫做pid它的父进程的id叫ppid通过getpid系统调用接口获取pidgetppid获取ppid。process.c1 #includestdio.h 2 #includeunistd.h 3 4 int main() 5 { 6 while(1) 7 { 8 printf(我是一个进程: 我的pid是%d: 我父进程的pid是%d:\n,getpid(),getppid()); 9 fflush(stdout); 10 sleep(1); 11 } 12 return 0; 13 }ls /proc #查看进程 ps axj [| grep process] #显示进程信息左侧蓝色的数字表示特点进程的pid还有一点要提的就是cwdcurrent work dir)表示当前所处路径进程启动时所处的路径,属于进度的基本属性之一为了支持进程访问文件时缺省路径的问题。FILE* fp fopen(log.txt,r); //这里log.txt就是缺省路径使用chdir可以改变路径。int chadir(const char *path)3.1 父进程与子进程3.1.1 bash什么是bashbash是命令行解释器本身也是一个程序它也作为终端中每一条命令的父进程也就是命令行中执行程序的父进程。3.1.2 forkfork的核心功能是用来创建子进程可以理解为父进程的一份拷贝采用写时拷贝只修改特定数据如pidppid所以fork创建的子进程和它的父进程共享一份代码但是只执行fork之后的代码那他们的数据也是共享的吗看如下代码。1 #includestdio.h 2 #includeunistd.h 3 4 void func() 5 { 6 int cnt 5; 7 while(cnt--) 8 { 9 printf(我是一个子进程: 我的pid是%d: 我父进程的pid是%d:\n,getpid(),getppid()); 10 fflush(stdout); 11 sleep(1); 12 } 13 } 14 15 int main() 16 { 17 int id fork(); 18 19 if(id 0) 20 { 21 //子进程 22 func(); 23 24 } 25 26 else if(id 0) 27 { 28 while(1) 29 { 30 printf(我是一个父进程: 我的pid是%d: 我父进程的pid是%d:\n,getpid(),getppid()); 31 fflush(stdout); 32 sleep(1); 33 } 34 } 35 return 0; 36 }运行结果第一个问题fork这个函数怎么返回了两次先说为什么要返回两次一个返回值用于确定子进程是否创建成功返回值0表示创建成功否则返回-1还有一个返回值是给父进程的返回的是子进程的pid0)因为父进程要管理子进程返回两次的原因是因为有两个进程各返回一次fork之前也就是分叉前只有当前一个进程fork后就有了父进程和子进程子进程是复制体共享代码段核心工作做完后一起执行返回值。第二个问题怎么id既等于0又能大于0看如下代码我们增加一个全局变量flag观察在两个进程中的值和地址1 #includestdio.h 2 #includeunistd.h 3 4 static int flag 10; 5 void func() 6 { 7 int cnt 5; 8 while(cnt--) 9 { 10 flag; 11 printf(我是一个子进程: 我的pid是%d: 我父进程的pid是%d: flag:%d flag:%p\n,getpid(),getppid(),flag ,flag); 12 fflush(stdout); 13 sleep(1); 14 } 15 } 16 17 18 int main() 19 { 20 int id fork(); 21 22 if(id 0) 23 { 24 //子进程 25 func(); 26 27 } 28 29 else if(id 0) 30 { 31 while(1) 32 { 33 printf(我是一个父进程: 我的pid是%d: 我父进程的pid是%d: flag:%d flag:%p\n,getpid(),getppid(),flag ,flag); 34 fflush(stdout); 35 sleep(1); 36 } 37 } 38 return 0; 39 }运行结果我们惊奇的发现flag的地址是相同的但是值却不相同咋滴量子纠缠呐狗头那肯定不是先要了解的是这的地址是虚拟地址它们实际的物理地址是分开的虚拟地址需要通过一定的运算找到它的真实物理地址这个后面会详细介绍先提一嘴。其他情况父进程结束了但是子进程还没结束。 1 #includestdio.h 2 #includeunistd.h 3 4 void func() 5 { 6 while(1) 7 { 8 printf(我是一个子进程: 我的pid是%d: 我父进程的pid是%d:\n,getpid(),getppid()); 9 fflush(stdout); 10 sleep(1); 11 } 12 } 13 14 int main() 15 { 16 int id fork(); 17 18 if(id 0) 19 { 20 //子进程 21 func(); 22 23 } 24 25 else if(id 0) 26 { 27 int cnt 5; 28 while(cnt--) 29 { 30 printf(我是一个父进程: 我的pid是%d: 我父进程的pid是%d:\n,getpid(),getppid()); 31 fflush(stdout); 32 sleep(1); 33 } 34 } 35 return 0; 36 } 运行结果这里的pid1实际上就是bash所以当父进程结束时会被bash接替因为子进程是需要被管理的。完~