当前位置: 首页 > Linux

进程控制

时间:2023-04-07 02:05:13 Linux

进程创建第一个进程:0号进程,是在操作系统内核启动过程中手动形成的。第二个进程:进程1,是在内核态通过fork从进程0派生出来的。其他进程:在用户态下,通过fork过来。创建进程(fork)注意:fork的返回值在不同的进程是不同的。在父进程中,fork的返回值是子进程的PID。在子进程中,fork的返回值为0,fork内部已经开始导流。根据判断当前是哪个进程,从而返回不同的值。fork前的代码只由父进程执行,fork后的代码由父子进程共同执行(但不确定这两个进程先调度哪个进程)。子进程创建后,操作系统会为子进程创建一个进程地址空间。和页表,但此时子进程的进程地址空间对应的物理地址与父进程的进程地址空间对应的物理地址相同,即父子进程使用一块同时占用物理内存(代码和数据共享)但是,当子进程或父进程更改数据时(例如子进程更改数据),子进程将执行“写时复制”,复制物理地址中的整个数据段,并将进程地址空间对应的虚拟地址映射到复制的物理地址。这样不会影响父进程的数据(进程是独立的)#include<pid_tfork(void);//返回值为进程的PIDfork创建失败系统中进程过多。真实用户进程超出限制。进程终止当程序结束,进程正常终止时,所消耗的系统资源(内存、IO等)将被完全释放。如果不释放,相应的资源就会丢失(异常终止)。linux系统设计规定:,操作系统会自动回收进程的所有资源(比如malloc申请的内存没有被free释放,进程结束后内存也会被释放),但是recovery操作系统只会回收进程在工作时消耗的内存和IO。进程终止方法不是回收进程本身占用的内存(主要是task_struck和栈内存),而是正常终止:程序正常结束,从main函数return返回。调用exit()函数退出进程。(voidexit(intstatus);)_exit(void_exit(intstatus);)异常终止:程序异常命令行输入ctrl+c发送退出信号。使用return、exit和_exit终止进程的区别。当使用return和exit终止函数时,已经被占用的资源(如linebuffer等)会被释放。使用_exit终止程序时,直接终止进程,不会释放系统资源。进程等待进程等待一般由父进程完成。父进程回收子进程的资源,通过进程等待获取子进程的退出信息。wait方法wait函数原型wstatus:用于返回子进程结束时的状态信息(传递一个int类型变量的地址即可)pid_t:这是返回本次wait恢复的子进程的PID。#include#includepid_twait(int*status);wait工作原理当子进程结束时,操作系统会向父进程发送一个SIGCHILD信号。当父进程调用wait函数时,会等待SIGCHILD信号(函数会阻塞在这里)。父进程收到信号后,会唤醒,然后回收僵尸进程(子进程退出但还没有被回收时的状态)。如果父进程没有子进程,但是调用了wait函数,wait函数会返回错误。如果父进程有多个子进程,等待函数将阻塞,直到其中一个子进程结束。所以如果父进程调用wait函数,那么一定是某个子进程先于父进程结束。waitpid方法wait和waitpid的区别基本功能是一样的,都是用来回收子进程的。但是waitpit可以回收指定PID的子进程。waitpit可以选择阻塞和非阻塞两种工作模式。waitpid函数原型#include#includepid_twaitpid(pid_tpid,int*status,intoptions);pid:指定要回收的子进程的PID(传值-1,表示不指定要回收的子进程)status:用于存放子进程结束时的状态信息(只传地址avariableoftypeint)options:实现一些特殊的功能。当传递的参数为0时:表示不使用此项(即使用阻塞)WNOHANG:如果没有子进程,则立即返回0(非阻塞)退出结果statusstatus为int类型,32位,只有当实际上使用了16位。状态的第8-15位是退出代码。异常退出时,status的低7位是终止信号(终止信号可以用kill-l显示)检测status退出状态的宏WIFEXITED(status):检查进程是否正常退出,如果所以,这是真的。WEXITSTATUS(status):如果进程正常退出,查看进程退出码。进程程序替换(exec函数)替换原理使用fork创建子进程后,父子进程执行同一个程序,但是为了让子进程执行不同的程序,往往需要调用一个exec函数来替换原程序中的子进程。当调用exec函数时,进程物理空间中的数据将被新程序完全替换,并重新建立映射关系,然后从新程序开始执行进程。注意:调用exec函数并没有创建新进程,所以调用前后进程的PID没有改变。因此,有了exec函数族,就可以将子进程中的代码单独编写,单独编译链接成一个可执行程序。当调用exec族函数时,会从新程序的启动代码开始加载并执行新的程序,并且不会返回当前代码,所以不会执行上一个进程的后续代码。替换函数execl和execv函数路径:要执行的可执行程序的完整路径。arg:传递给可执行程序的参数。...:可变参数,表示可以传递多个参数,但最后一个参数必须为NULL。argv[]:参数数组,传递的参数必须提前写入数组。调用失败则返回-1,调用成功则执行新程序,不返回。intexecl(constchar*path,constchar*arg,.../*(char*)NULL*/);intexecv(constchar*path,char*constargv[]);例如:执行ls程序,传递参数-a-l这里的第一个参数ls好像没有作用,只是一个占位符,第二个起始参数会传递给程序。execl("/bin/ls","ls","-l","-a",NULL);execlp和execvp函数和上面两个函数一样,但是上面两个只能指定可执行程序的全名Path(否则找不到文件,会报错)而且这两个函数只能通过可执行程序的文件名,或完整路径。它会先到当前目录下寻找文件,找到后直接执行。如果没有找到,就会到环境变量PATH指定的目录中查找,如果还是没有找到,就会报错。intexeclp(constchar*file,constchar*arg,.../*(char*)NULL*/);intexecvp(constchar*file,char*constargv[]);execle和execvpe函数执行executable程序时,会额外传递一个环境变量的字符串数组envp给要执行的程序。传递的环境变量将替换默认环境变量。当找不到文件时,会在这个环境变量中寻找,而不是默认的环境变量PATH。intexecle(constchar*path,constchar*arg,.../*,(char*)NULL,char*constenvp[]*/);intexecvpe(constchar*file,char*constargv[],char*constenvp[]);