进程控制:创建、退出、等待、替换
-
创建:
pid_t fork(void)—通过复制父进程创建一个子进程。(代码共享,数据独有)
返回值:父进程返回值大于0(子进程pid);子进程返回0;出错返回-1
写时拷贝技术:创建子进程后,子进程复制了父进程,因此父子进程一开始映射的是同一块物理内存,但是当内存数据要发生改变的时候,则重新为子进程开辟空间,拷贝数据过去。—创建子进程效率高pid_t vfork(void)—创建一个子进程并阻塞父进程。(父子进程共用虚拟地址空间)
父子进程共用栈区,如果同时运行就会造成栈混乱,因此vfork阻塞父进程,让子进程先运行,直到子进程exit退出或者程序替换后,父进程才会运行。 -
退出:
main函数中return
库函数:void exit(int status)—可以在任意位置调用退出进程,在退出前会刷新缓冲区
系统调用:void _exit(int status)—可以在任意位置调用退出进程,但是会直接释放资源,不刷新缓冲区
获得进程退出返回值:echo $?退出场景:
正常退出:通过以上三种方式退出进程
异常退出:程序因为某种错误中间崩溃退出查看上一次系统调用使用错误的原因:
void perror(const char* s)
char* strerror(int errnum) -
进程等待:
父进程等待子进程退出,获取退出子进程返回值,释放退出的子进程资源—避免产生僵尸进程接口头文件:#include<sys/wait.h>
pid_t wait(int* status)—阻塞接口
等待任意一个子进程退出,通过status获取退出返回值,释放资源。
返回值:成功则返回退出子进程的pid>0;错误返回-1pid_t waitpid(pid_t pid, int* status, int options)
可以等待任意一个子进程退出,也可以等待指定的子进程退出
可以阻塞等待子进程退出,也可以非阻塞等待子进程退出。
参数设置:pid:-1—等待任意子进程;大于0—等待指定子进程;
options:0—默认阻塞等待;WNOHANG-非阻塞等待
返回值:成功则返回退出子进程的pid>0;没有子进程退出返回0;错误返回-1阻塞:为了完成一个功能,发起一个调用,若功能完成条件不具备,一直等待。
非阻塞:为了完成一个功能,发起一个调用,若功能完成条件不具备,立即报错返回。注意:wait/waitpid是只要有已经退出的子进程,则会直接处理,不需要等待
pcb里保存进程退出返回值时到底是怎么保存的?获取的status值到底是什么数据?

注意:WIFEXITED返回真代表进程正常退出,之后才可使用WEXITESTATUS
进程等待以及查看子进程退出返回值的代码实现:
#include <stdio.h> //printf
#include <stdlib.h> //exit
#include <unistd.h> //fork
#include <sys/wait.h> //wait
int main()
{
pid_t pid = fork(); //创建子进程
if(pid < 0)
{
perror("fork perror"); //若返回值小于0代表子进程创建失败
return -1;
}
else if(pid == 0)
{
printf("i am child process\n"); //返回值等于0代表是子进程
sleep(5);
exit(99); //五秒后子进程退出,退出码为99
}
int ret, status;
while((ret = waitpid(-1, &status, WNOHANG)) == 0) //父进程循环非阻塞等待子进程退出,并获取子进程返回值status
{
printf("当前子进程还没有退出\n"); //若waitpid返回值为0表示当前子进程还没有退出
sleep(1);
}
if(ret < 0) //waitpid出错返回-1
{
perror("waitpid error");
}
if((status & 0x7f) != 0) //低7位为异常退出信号值,若为0表示进程正常退出
{
printf("进程异常退出");
return -1;
}
int retval = (status >> 8) & 0xff; //低16位中的高8位为进程正常退出的返回值
int coredval = (status >> 7) & 0x01; //获取coredump标志位
printf("%d-%d, exit-retval:%d, coredval:%d\n", ret, pid, retval, coredval); //打印子进程pid,退出码以及coredump标志位
return 0;
运行结果:

-
程序替换:替换一个进程正在调度运行的程序(加载一个新的程序到内存中,更新当前进程的页表映射信息到新的程序上)
exec函数族:5个库函数+系统调用接口
extern char** environ;
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, char* const argv[]);
int execvp(const char* file, char* const argv[]);
int execve(const char* path, char* const argv[], char* const envp[])
3类参数:新的程序路径名称;程序运行参数(最后必须要以NULL作为结尾);自己设定环境变量execl和execv的区别:程序运行参数的不同设置方式
例:execl("/bin/ls", “ls”, “-a”, “-l”, NULL)
char* argv[] = {“ls”, “-a”, “-l”, NULL};execv("/bin/ls", argv)execl(execv)和execlp(execvp)的区别:新的程序是否需要带路径,指定程序所在位置
execl("/bin/ls", …)
execlp(“ls”, …)—原因是会到PATH环境变量指定的路径下去找对应程序,适用场景:要替换的为命令程序(也可以通过指定新程序的路径实现功能)execl(execv)和execle(execve)的区别:当前进程的环境变量是否由自己来设置
execl("/bin/ls", …)—使用默认当前就有的环境变量
char* env[] = {“MYVAL=1000”, NULL};execle("/bin/ls", …, NULL, env)—直接替换原有环境变量,而非追加,即此时只有一个环境变量MYVAL
exec函数族测试:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("我要进行程序替换啦~~\n");
//extern char** environ; //获取当前进程环境变量
//char* env[] = {"MYVAL = 1000", NULL}; //自己设置当前进程环境变量
execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
//execlp("ls", "ls", "-a", "-l", NULL);
//execle("/usr/bin/ls", "ls", "-a", "-l", NULL, env);
//char* argv[] = {"ls", "-a", "-l", NULL}; //定义指针数组存储程序运行参数
//execv("/usr/bin/ls", argv);
//execvp("./myenv",argv);
//execve("./myenv", argv, environ);
printf("程序替换结束\n");
return 0;
}
①execl,execlp,execv,execvp运行结果:

②通过自己设置当前进程的环境变量测试execve
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("我要进行程序替换啦~~\n");
extern char** environ; //获取当前进程环境变量
char* env[] = {"MYVAL = 1000", NULL}; //自己设置当前进程环境变量
//char* argv[] = {"ls", "-a", "-l", NULL}; //定义指针数组存储程序运行参数
execve("./myenv", argv, env);
printf("程序替换结束\n");
return 0;
}
打印当前输入命令参数以及当前进程环境变量:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
for(int i = 0; argv[i] != NULL; i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
extern char** environ;
for(int i = 0; environ[i] != NULL; i++)
{
printf("environ[%d] = %s\n", i, environ[i]);
}
return 0;
}
运行结果:

1556

被折叠的 条评论
为什么被折叠?



