进程1.进程是正在进行中的程序进程程序的一次执行过程程序的实例进程在运行过程中时需要用到内存和cpu内存和cpu就是进程需要用到的资源2.进程和程序的关系a.out 存放在硬盘上 --- 静态./a.out 硬盘上的a.out被加载到内存运行起来 --- 动态进程 --- 由程序加载到内存运行起来后产生的程序每运行一次都对应一个新的进程命令查看进程top //类似任务管理器3.进程的组成程序 数据 代码程序 data bss text进程 PCB [堆|栈|data|bss|text]C语言中5个区栈、堆、全局区静态区、字符串常量区、代码区text --- 代码区data --- 全局区中初始化了的数据bss --- 全局区中未初始化的数据4.进程的作用保存当前运行相关信息进程 --- 描述程序动态运行过程记录和保存程序运行过程中的动态信息5.进程的状态查看进程的状态ps aux | grep a.out //查看进程pid号以及状态ps -eLf | grep a.out //查看进程的ppid号和pid号PID --- process idPPID --- parent process idkill -信号编号 进程的pid信号9SIGKILL19SIGSTOP18SIGCONTlinux系统中通过进程树管理进程进程树 --- 类似家族族谱6.进程相关APIa进程创建b进程的执行c进程退出d进程回收进程创建fork#include sys/types.h #include unistd.h pid_t fork(void)功能创建子进程参数空返回值成功 父进程中返回子进程的pid子进程中返回0失败 返回-1并且errno被设置注意1.fork后谁先运行 --- 运行顺序不确定2.fork之后父子进程拥有独立的4G内存空间32位系统父子进程各自拥有自己的数据段互相不会直接影响进程的执行exec 函数int exec l(const char *path, const char *arg, ...); int exec lp(const char *file, const char *arg, ...); int exec le(const char *path, const char *arg,..., char * const envp[]); int exec v(const char *path, char *const argv[]); int exec vp(const char *file, char *const argv[]); int exec vpe(const char *file, char *const argv[], char *const envp[]);功能执行一个新程序用新进程的镜像替换原有进程的镜像镜像 --- 就是它的组成部分进程 [text|data|bss|堆栈] pcb //除开pcb就是镜像部分int exec l(const char *path, const char *arg, ...); int exec v(const char *path, char *const argv[]);参数path 表示要执行文件的路径 --- 要求路径名中要包含可执行文件名arg 表示的是可执行文件的名字... 可变参数 最终以NULL结尾 //给的是可执行文件需要用到的参数l --- list 逐个罗列从第二个参数开始罗列v --- vector 表示从第二个参数开始组成数组的形式egls -l / execl(/bin/ls,ls,-l,/,NULL); char *const args[] {ls,-l,/,NULL}; execv(/bin/ls, args);which ls //查看可执行文件路径带P --- path表示寻找可执行文件到系统的环境变量PATH中寻找此时不需要指定路径file参数 --只需要指定可执行文件的名字即可int execlp ( const char *file, const char *arg, ...); int execvp ( const char *file, char *const argv[]);带e --- environment --- 环境变量如果要执行的文件需要用到环境变量的时候则可以通过带e的这两个函数传统环境变量给可执行文件int exec l e(const char *path, const char *arg,..., char * const envp[]); int exec vp e(const char *file, char *const argv[], char *const envp[]);int execle(可执行文件路径, 可执行文件名字,可执行文件用到的参数..., 环境变量);env --- 打印当前系统的环境 extern char **environ; //系统环境变量指针 execle(/usr/bin/env,env,NULL,environ);系统环境变量相当于是存放在一个 char * 的指针数组中strtokchar *strtok(char *str, const char *delim);功能提取字符串参数str 要解析的字符串 --- 给成NULL表示接着原先的字符串继续拆分delim 分隔标记返回值成功 返回子字符串的首地址失败 返回NULL字符串解析完也返回NULL注意如果对一个字符串进行连续拆分 --- strtok(NULL, :;);进程退出结束进程终止8种情况1.main中return2.exit //库函数C语言库函数会执行IO库的清理工作关闭所有的流 和 所有打开的文件注册清理函数 atexit3._exit _Exit //系统调用会关闭所有已经打开的文件不执行清理函数4.主线程退出5.主线程调用pthread_exit异常终止6.abort //发送一个SIGABRT7.signal 发信号结束了进程 kill pid -98.最后一个线程被pthread_cancelexit _exit函数退出状态终止进程会通知父进程自己如何终止的如果是正常结束终止则由exit传入参数如果是异常终止则由内核通知异常终止原因的状态任何情况下父进程都可以使用waitwaitpid获得这个状态以及资源回收void exit(int status) exit(1);功能让进程退出并刷新缓存区参数status 进程退出的状态返回值空status 0377 1111 1111 EXIT_SUCCESS 0 EXIT_FAILURE 1return 当该关键字出现在main函数中时可以结束进程如果在其他函数中则表示结束该函数exit - 刷新缓存区 - atexit注册的退出函数 - _exit_exit 系统调用void _exit(int status);功能让进程退出不刷新缓存区参数status 进程退出状态返回值空回调函数atexitint atexit(void (*function)(void));功能注册进程退出前执行的函数参数function 函数指针指向void返回值void参数的函数指针返回值成功 返回0失败 返回非0当程序调用exit 或 main函数执行return时所有用atexit注册的退出函数将会由注册时的顺序倒序被使用注意1.exit函数被调用时才会调用atexit函数_exit函数调用时不会调用atexit注册的函数2.atexit程序正常结束1main返回2exit3.atexit函数可以多次注册4.最后“退出清理函数”的调用顺序与注册顺序相反wait 、waitpid#include sys/types.h #include sys/wait.h pid_t wait(int *wstatus); pid_t wait(int *status);//wait 来获取到功能该函数可以阻塞等待任意子进程退出并回收该进程的资源和获取退出状态值一般用在父进程回收子进程状态参数status 进程退出时的状态如果不关心其退出状态一般用NULL表示// 如果要回收进程退出状态则用WEXITSTATUS回收。返回值成功 返回回收的子进程pid号失败 返回-1注意1.wait是阻塞操作exit(status); ---int status; wait(status); WIFEXITED(wstatus) //判断是否是正常结束 WEXITSTATUS(wstatus) //获取正常结束时的退出状态值 WIFSIGNALED(wstatus) //判断是否时信号结束的 WTERMSIG(wstatus) //是哪个信号waitpid 更灵活pid_t waitpid(pid_t pid, int *wstatus, int options); pid_t waitpid(pid_t pid, int *status, int options);pid-1 指定进程组内的任意子函数eg:-100等待 GID 100 的组里面的 任意子进程-1 回收任意子进程组内外eg:-1 等待(父进程)任意子进程0 回收和当前调用waitpid一个组的所有子进程组内eg:等待 GID 调用进程PID 组中的 任意子进程0 回收指定ID的子进程eg:100等待 pid 为 100的这个子进程 的状态改变等待指定的PID的进程的 子进程注意waitpid (-1,a,0) wait(a);参数status 子进程退出时候的状态如果不关注退出状态用NULLoption 选项0 --- 表示回收过程会阻塞等待WNOHANG --- 表示非阻塞模式回收资源返回值成功 返回接收资源的子进程pid非阻塞是返回值0表示没有任何子进程状态改变失败 返回-1注意waitpid(-1,status,0) wait(status);1.如果所有的子进程都在运行在阻塞状态2.如果一个子进程终止正在等待的父进程则获得终止状态获得子进程的状态后立刻返回3.如果没有子进程则立即出错退出wait 和 waitpid功能都是用来等待子进程状态改变的wait 阻塞版本子进程的结束状态waitpid 可以实现非阻塞的等待还可以检测子进程的其他状态改变如果waitpid实现非阻塞回收想要实现收尸操作必须使用while