进程 ---(多任务并行) 进程程序的一次执行过程也叫做程序的实例.c编译出来的a.out只是躺在硬盘上的“死文件”只有被exec加载到内存后才变成活着的“进程”。这里的a.out被加载后也是其他程序的子进程进程的组成栈区Stack存放局部变量、函数调用帧、返回地址。堆区Heap动态分配malloccalloc堆内存必须由程序员手动释放。数据区Data又称静态区data 段已初始化的全局变量和静态变量。.bss 段未初始化的全局变量文本区Text只读的机器指令PCB进程表项task_structPCB包含PID进程ID、PPID父进程ID、进程状态就绪/运行/阻塞)、优先级。还保留有cpu中寄存器的值切出切入cpu所需打开的文件描述符当前目录。程序的组成所谓的死文件数据变量代码。pid_t fork(void);fork后会产生一个新的进程父进程返回值是子进程的pid子进程的返回值是0一次调用两次返回。失败返回-1fork后子进程拥有的数据几乎与父进程相同但是不共享stactic的变量、全局变量、甚至堆区的变量都是各自用各自的。父子之间难以对互相造成影响这保证了进程的独立与安全也带来了信息难以互通的难题。fork后谁先运行由调度算法决定假设父进程先退出子进程会被系统进程收养。收养后子进程pid不变假设子进程先死而父进程没有回收资源wait子进程会变为僵尸态占用内存。void exit(int status)功能: 让进程退出,并刷新缓存区参数status:进程退出的状态冷知识return 0会被编译为exit0exit - 刷新缓存区 - atexit注册的退出函数 - _exitint atexit(void (*function)(void));atexit注册了一个函数令进程在退出调用exit0或者return前执行此函数。与_exit(0)相对比exit0是更规范、更温柔的退出。pid_t wait(int *status);wait是阻塞操作会等待任意子进程结束后接收返回值其通过int *status得到的值并非一个单纯的整型返回值它被分割为了三部分0~6位是终止信号编号7位是是否产生Core Dump8~15位才是exit的返回值。故而通过宏来查看其传输的信息WIFEXITED(wstatus)检查wstatus的低7位终止信号位是否全为0。全为0说明进程是正常退出exitreturn_exit())返回值为真时说明低七位不是0可以通WIFSIGNALED(wstatus)获得其终止信号编号WEXITSTATUS(wstatus)获取正常调用exit退出时exit中的值如果执行成功则返回子进程识别码(PID)如果有错误发生则返回-1。失败原因存于errno中。pid_t waitpid(pid_t pid, int *status, int options);pid-1 回收指定进程组内的任意子进程通过setpgid()可以改变进程组id-1 回收任意子进程组内外0 回收和当前调用waitpid一个组的所有子进程组内0 回收指定ID的子进程options0 表示回收过程会阻塞等待WNOHANG 表示非阻塞模式回收资源。如果执行成功则返回子进程识别码(PID)如果有错误发生则返回-1。失败原因存于errno中。pid_t getppid(void);返回目前进程的父进程识别码pid。pid_t getpid(void);返回目前进程的进程识别码pid。若父进程在子进程存活的情况下结束了会被systemdpid1的子进程systemd收养【ubuntu 18.04 linux 5.4】同理若父进程在有僵尸子进程的情况下结束了僵尸子进程会被systemdpid1的子进程systemd收尸wait通过创建子进程和exec能够实现一个简单的my_shellwhile(1) { char p[1024] {0}; fgets(p, 1024, stdin); // 读一行命令 int len strlen(p); p[len-1] \0; // 去掉末尾换行符 if(strcmp(p,quit)0 || strcmp(p,exit)0) return 0; // 退出循环 char *s[10] {NULL}; s[0] strtok(p, ;:); // 按空格、分号、冒号分割 if (s[0] NULL) continue; // 避免空命令 int i 0; while(s[i] strtok(NULL, ;:)) ; // 继续分割填充 s[1]...s[9] if(fork() 0) { execvp(s[0], s); // 子进程执行命令 } else { wait(NULL); // 父进程等待 } }