进程
程序和进程
- 进程是程序运行的实例,程序是可执行的二进制代码文件,将文件加载到内存中运行就得到一个进程,同一个程序文件家在多次称为不同的进程
- 进程包括三个部分:代码段、数据段、堆栈段。
- 代码段就是程序的代码数据,如果有多个进程运行同一个程序,则可以使用同一个代码段
- 数据段存放程序的全局变量、常量和静态变量
- 堆栈段中的栈用于函数调用,存放函数的参数、函数内部定义的局部变量。堆栈段还包括进程控制块(PCB)
- PCB处于进程核心堆栈的底部,PCB是进程存在的唯一标识
- 每个进程在系统中通过PID唯一的标识
进程的创建和结束
- 进程创建有两种方式:由操作系统创建、由父进程创建
- init()函数在内核态运行,是内核代码
- init进程是内核启动并运行的第一个用户进程,运行在用户态下
- init函数调用execve()从文件/etc/inittab中加载可执行程序init并执行,这个过程没有调用do_fork()
进程创建 fork()函数
1 | #include <unistd.h> |
- 调用fork()函数的就是父进程,新创建的进程就是子进程
- 为新创建的子进程分配进程空间,将父进程的空间中的内容复制到子进程的进程空间,包括数据段和堆栈段,两者共用代码段
getpid()
获得当前进程的PID,getppid()
获得父进程的PID
进程结束 exit()函数
1 | #include <stdlib.h> |
- exit()是一个函数,执行完成后将控制权交给系统,而return完成后将控制权交给调用函数
- exit是正常终止,abort是异常终止
- exit在stdlib.h中声明,_exit在unistd.h中声明
- exit参数为0表示进程正常终止,如果是其他值则表示执行过程中有错误发生
- _exit在执行后立即返回给内核,会关闭所有的文件描述符,清理内存以及其他一些内核清理函数,但是不会刷新流。exit()要先执行一些清除操作,然后才将控制权交给内核,是在_exit函数基础上的一个封装,会在调用_exit函数之前先刷新流数据,有利于将缓冲区的数据正确写入文件,如printf()函数就是一个使用缓冲IO的方式
僵尸进程
- 孤儿进程是指,父进程退出后,有子进程还在运行,这些子进程就是孤儿进程,这些进程将会被init进程(进程号PID=1)的进程收养
- 僵尸进程,是指进程使用fork创建紫禁城,如果子进程退出,而父进程没有调用wait或者waitpid获取子进程的状态信息,则子进程的进程描述符仍然保存在系统中,这种进程称为僵尸进程
- 孤儿进程是子进程未退出,父进程已退出。僵尸进程是子进程已退出,父进程未退出
- 调用wait函数,可以自动分析当前进程的某个子进程已经退出,wait可以回收子进程,销毁后返回,如果没有这样的子进程wait就会一直阻塞在这里,直到有一个出现
1
2
3
4
5
6
7#include <sys/tyoes.h>
#include <sys/wait.h>
pid_t wait(int *status);
//wait会暂时停止目前进程的执行明知道有信号或者子进程结束
/*如果在调用wait时已经有子进程结束,则wait会立即返回子进程结束状态值,子进程结束状态值由参数status返回,子进程的进程识别码也会一起返回,如果不需要结束状态值,则参数status可以设为NULL*/
//执行成功则返回子进程识别码PID,如果错误返回-1,并将错误原因存在errno
1 | #include <sys/types.h> |
- waitpid是wait的封装,多出两个可由用户控制的参数pid和options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
//暂时停止目前进程的执行,直到有信号来到或子进程结束
//pid是等待的子进程的识别码,pid<-1等待进程组识别码为pid绝对值的任何子进程
//pid=-1等待任何子进程,相当于wait
//pid=0等待进程组识别码与目前进程相同的任何子进程
//pid>0等待任何子进程识别码为pid的子进程
//options=WNOHANG及时没有子进程退出,立即返回
//options=WUNTRACED,子进程进入暂停则马上返回,结束状态不予理会
//正常返回时返回收集到的子进程的进程ID
//如果设置了WNOHANG,调用中waitpid发现没有已退出的子进程可手机则返回0
//如果调用中出错,则返回-1,errno被设置成相应的值指示错误
//pid指示的子进程不存在,若进程存在,但不是调用进程的子进程,waitpid就会出错返回,errno被设置成ECHILD?
守护进程
- 守护进程是脱离终端并且在后台运行的进程
- 创建简单的守护进程:
- 创建子进程,父进程退出
- 在子进程中创建新会话,使用系统函数setsid创建一个新会话,并担任会话组组长setsid()
- 改当前目录为根目录chdir()
- 重设文件权限位掩码为0,用umask(0)
- 关闭文件描述符