进程控制

    xiaoxiao2023-11-12  141

    进程创建

    fork函数原型

    #include <unistd.h> pid_t fork(void);//创建子进程

    内核执行流

    分配新的内存块和内核数据结构给子进程(创建task_struct)将父进程部分数据结构内容拷贝至子进程(拷贝父进程的task_struct内容)添加子进程到系统当中(分配新的内核堆栈、新的pid,再将子进程PCB添加到链表)fork返回,开始调度器调度

    进程执行流

    fork之前父进程独立执行,fork之后父子进程分别执行,谁先执行有调度器决定

    fork返回值

    fork有两个返回值,父进程返回子进程的pid,子进程返回0一个父进程有多个子进程,一个子进程有一个父进程,fork之后父进程需要知道那个子进程完成任务,所以父进程返回子进程的pid当fork失败返回-1,PCB是要占内存的,当内存不够或者实际用户进程超过了限制fork会调用失败

    fork常规用法

    父进程希望复制自己,使父子进程同时执行不同的代码段一个进程要执行一个不同的程序

    vfork和fork

    vfork也可以创建子进程,vfork创建的父子进程共享地址空间,fork创建的父子进程具有独立的地址空间vfork保证子进程先运行,调用exec或exit之后父进程才能被调度运行,fork父子进程分别执行,执行顺序由调度器决定

    进程终止

    进程退出场景

    代码运行完毕,结果正确代码运行完毕,结果不正确异常终止

    进程退出方法

    查看进程退出码

    echo $?

    正常终止

    main函数返回_exit #include <unistd.h> void _exit(int status); //status定义进程终止状态,父进程通过wait获取 //status仅有低8位可被父进程所用 exit:先执行用户通过atexit或on_exit定义的清理函数,然后关闭所有打开的流,所有缓存数据均被写入,最后调用_exit #include <unistd.h> void exit(int status);

    exit与_exit的执行流

    return:return n同等于exit(n),调用return会将返回当做exit的参数

    异常终止

    ctrl+c:信号终止kill -9 pid:向进程ID为pid的进程发出9号信号

    进程等待

    为何存在进程等待

    子进程退出,父进程不管不顾会造成僵尸进程,僵尸进程会造成内存泄漏,就算是”kill -9“也无法终止进程,因为无法杀死死去的进程所以父进程需要知道子进程的任务完成如何,父进程可以通过进程等待的方式获取子进程资源和退出信息

    进程等待方法

    wait

    #include <sys/types.h> #include <sys/wait.h> pid_t wait(int* status); //成功返回被等待进程的pid,失败返回-1

    waitpid

    #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int* status, int options); //当pid>0时,只等待进程ID为pid的子进程,当pid=0时,等待同一个进程组中的任何子进程 //当pid=-1时,等待任何子进程,当pid<-1时,等待指定进程组的中的任何子进程 //options:WNOHANG非阻塞式,WUNTRACED阻塞式,WUNTRACED涉及到跟踪方面的知识,并且很少用 //当正常返回时waitpid返回收集到的子进程的pid //当设置了WNOHANG,而调用中waitpid发现没有退出的子进程可收集,返回0 //当调用出错时,返回-1,此时errno设置成相应的值以指示错误所在

    wait和waitpid的参数status

    status是一个输出性型参数,由操作系统填充如果传递NULL,表示不关心子进程的退出状态信息WITFEXITED(status):查看子进程是否正常退出,若为正常终止子进程返回的状态,则为非零,否则为0WEXITSTATUS(status):查看进程退出码,若WIFEXITED非零,提取子进程退出码,否则这个值毫无意义上述的WITFEXITED和WEXITSTATUS是宏,用来读取子进程退出状态status不能简单当做整形,可以当位图看待,只研究低16位,当正常终止时,status的8-15位代表退出码,0-6位为0,当异常退出时,0-6为为退出码

    注意

    如果子进程已退出,调用wait/waitpid时,wait/waitpid会立即返回,并释放资源,获取子进程退出信息如果子进程存在且正常运行,调用wait/waitpid时,进程可能会阻塞如果不存在子进程,则立即出错返回

    进程程序替换

    替换原理

    用fork创建子进程后执行的是和父进程相同的程序,也可执行不同的代码分支,一般子进程和父进程做不同的事,否则这个子进程无意义,所以子进程调用exec函数替换子进程的程序和数据当进程调用exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动列程开始执行调用exec函数时并不创建新的进程,所以进程的id未改变

    替换函数

    int execl(const char *path, const char* arg, ...); int execlp(const char *file, const char* arg, ...); int execle(const char *path, const char* arg, ..., char* const envp[]); int execv(const char *path, const char arg[], ...); int execvp(const char *file, const char arg[], ...); int execle(const char *path, const char arg[], ..., char* const encp[]);

    助记

    exec+l(list):参数采用列表exec+v(vector):参数采用数组execl/execv+p(path):自动搜索的环境变量execl/execv+e(env):自己维护的环境变量

    函数解析

    调用成功加载新的程序从启动代码段开始执行,无返回值,调用失败返回-1execve为系统调用其他五个函数都是在execve上包装的

    exec函数关系

    函数与进程的相似性

    exec/exit类似于call/return一个C程序有许多函数,一个函数可以调用另一个函数,同时传递一些参数,每个函数都有它的局部变量,不同函数通过call/return系统进行通信一个C程序可以fork/exec另一个程序,同时传递一些参数,调用它的进程可以通过wait获取exit的返回值通过参数和返回值在拥有私有数据的函数间通信时结构化程序设计基础

    最新回复(0)