进程
- 进程是一个程序执行的实例,程序是静态的,而进程是动态的,进程是操作系统分配资源的基本单位。每个进程都有自己的独立地址空间,进程之间是独立的,如果需要知道其他进程的数据信息,就需要进程通信了。管道只适用于父子进程之间的通信,其他进程间通信可以使用消息队列,共享内存,信号量(用于实现进程同步),socket套接字。操作系统用PCB来描述一个进程。PCB(进程控制块),包括了进程的id(pid),进程的状态,进程的优先级,程序计数器,内存指针等。Linux下的PCB是一个结构体,名为task_struct.
- 进程的创建:Linux操作系统下用 int fork(),来创建进程。调用fork函数的进程为父进程,新创建的进程为子进程,可以通过fork函数返回值来确认父子进程(返回值大于0是父进程,等于为子进程,小于0创建失败);创建新进程就是分配新的PID,创建新的PCB,然后拷贝父进程PCB中的大部分数据,子进程完全与父进程相同,但一般来讲子进程会执行exec系统调用,出于效率考虑,操作系统会采用写时复制,只有当父子进程要对相应段进行更改时,才会给子进程分配物理空间。也就是说,在fork之后,exec之间,子进程所用的代码段,栈,堆,数据段,实际映射的都是父进程的物理内存,父子进程虚拟地址映射出来的物理内存是相同的。如果不是exec,操作系统会给子进程重新分配堆栈,数据段,分配新的物理空间(至此父进程数据完全独立,互不干扰,但代码段物理空间相同),若执行了exec,则子进程的代码段也会重新分配物理空间。 最后将子进程加入就绪队列中。而父进程和子进程执行的先后顺序不确定的,取决于操作系统调度。
- **PCB进程控制块:**包括了进程的ID(PID),进程的状态,进程的优先级,内存指针,程序计数器等。PID-唯一的进程标识,如0号进程(交换进程),1号进程(Init进程,负责系统启动),2号进程(页精灵进程-负责虚拟内存请页);进程的状态:基本状态(就绪-运行-阻塞),Linux下可分为RSDTZX,6种状态:可执行-可中段睡眠-不可中断睡眠-暂停-僵尸-死亡。
- 进程同步:在多道程序设计系统中,同一时刻可能有许多进程,这些进程之间存在两种基本关系:竞争关系和协作关系。进程并发运行时,多个进程之间也可能会对某个临界资源进行请求,所以存在一种竞争关系,所以操作系统需要协调各个进程之间的竞争关系,就需要互斥,来保证同一时刻资源访问的唯一性。竞争资源可能会出现两中状况:死锁,饥饿;死锁:因多个进程对同一资源的竞争而造成一种僵局的状态 。饥饿:因为优先级而始终得不到资源的状况。 协作,多个进程需要进行配合,只有前面的进程完成了某些工作,并且通知后面的进程,后面的进程被唤醒后,才能进行工作,这就是一种同步关系。经典的例子就是消费者生产者问题.方法:信号量,互斥量。
- 进程控制:进程退出后,需要父进程接受其推出状态,并通知操作系统对资源回收。常在父进程中使用wait(int status),waitpid(int pid,int status,int flag);wait成功返回pid,失败返回-1,参数是输出型参数,保存子进程推出状态,不关心可以设置为NULL。waitpid,可以等待指定pid的进程,参数pid>0等待指定,pid=-1,等待任意进程,pid<-1,等待进程组id等于pid的绝对值的任意子进程。搭配第三个参数的WNOHANG在没有进程推出的时候会不阻塞返回0;