一、进程结构
进程是运行起来的程序?在内存中的程序?
怎么理解上面两句话?这里的程序是c语言c++代码编译后的可执行程序,存储在磁盘中。根据冯诺依曼体系结构,要运行这个程序,首先要把它加载也就是拷贝到内存中,这个工作是由操作系统完成的。
我们可以同时启动多个进程,所以内存中一定会加载多个程序,有多个程序,操作系统就要把它们管理起来。如何管理?先描述,再组织。由于Linux操作系统是C语言写的,所以要描述进程,肯定用struct描述。首先要有一个struct结构体,里面要存储进程的属性等(这就是描述),再通过双链表将多个结构体组织管理起来(这是组织)。
struct PCB
{
//id
//代码地址和数据地址
//状态
//优先级
//链接字段
struct PCB *next; //?详细见下文
}
上面这个结构体对象叫做进程的PCB(process control block)进程控制块。
PCB是内核数据结构,只在内存中出现,是进程属性的集合,创建进程时,操作系统会在内存中new或者malloc一块内存给PCB
PCB是所有操作系统PCB的统称,在Linux中,PCB具体是struct task_struct{},属性有
struct task_struct
{
//进程对应的标识符,pid
//父进程标识符 ppid,父进程一般是命令行解释器bash
}
如何以双链表链接?如上图
每启动一个可执行程序加载到内存,操作系统都会生成一个PCB对象并链接到链表上。对可执行程序的管理就变成了对PCB的管理。
CPU在执行进程时,并不直接访问可执行程序,而是找到对应进程的PCB,根据PCB找到可执行程序的代码和数据,交给CPU。
如果某个进程想退出,操作系统可以通过PCB找到可执行程序的代码和数据并释放掉,再把进程的PCB从链表中删掉,操作系统就不再管理这个进程了。对进程的管理就变成了对链表的增删查改
所以什么是进程?进程 = 可执行程序 + 内核数据结构(PCB)
二、父子进程的关系
如何创建进程?
1.在命令行中直接启动进程,即进行指令操作,其本质就是创建并执行了一个进程。
2.用代码创建进程
启动进程本质是创建进程,一般由父进程创建。操作系统生成PCB,但里面的内容大部分都是从父进程拷贝过来的。(形成父子关系)
命令行启动的进程其父进程都是bash。
查看进程的第一种方式:
ps axj | grep processname//可执行程序的名字
查看进程的第二种方式:查看/proc
1.一个进程能够找到自己的可执行程序
2.每个进程都要有自己的当前工作目录
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
chdir("/home/hanye/newdir");
FILE* fp = fopen("log.txt", "w");
if(fp == NULL) return -1;
fclose(fp);
while(1)
{
printf("pid:%d\n", getpid());
sleep(1);
}
return 0;
}
改变工作目录为/home/hanye/newdir后,可以看到
用代码创建进程
fork为什么有两个返回值?因为执行到return时,fork的核心工作已经完成了,子进程已经创建出来了,return也会被共享。
进程具有独立性,体现在有独立的PCB。要有独立性,进程之间不能相互影响,操作系统要保证父子进程要共享代码,并有各自独立的数据。