对进程的相关操作:
进程创建, 进程等待, 进程终止
创建进程
vfork函数
vfork创建的进程子进程先运行,子进程不退出父进程不运行,因为父子进程用相同的地址空间 如果不这样会造成栈混乱(子进程excit退出或者程序替换
fork的使用
NAME
fork - create a child process
SYNOPSIS
#include <unistd.h>
pid_t fork(void);
原理:通过复制调用进程创建子进程子进程复制父进程的PCB(代码共享 子进程不是从头开始的,数据独有)
返回值:父进程返回的是子进程的pid,子进程返回的是0,通过fork()的返回值判断父子进程
进程终止:
main函数return’ 释放资源刷新缓冲区
exit 释放资源刷新缓冲区
_exit 释放资源系统调用 (用户态)
进程返回值
perror
strerror
进程等待:
等待子进程退出,获取退出码,允许释放资源避免产生僵尸进程父进程不知道子进程啥时候退出,因此只能等待
**wait函数是一个阻塞函数 等待子进程退出wait();,返回值为子进程PID出错-1
**
pid_t waitpid(pid_t pid , int * status , int options)等待任意的子进程
pid 指定的进程ID
-1任意子进程
=0 没有子进程退出
/>0 等待指定子进程
status: 用于获去返回值
option: 选项
WNOHANG //将waitpid的改为非阻塞
阻塞:为了完成某个功能发起调用,一直等待直到完成
**非阻塞:**如果任务没有完成就放弃
程序替换
替换进程所运行的程序,让子进程完成其他功能
execl;
execlp;
execle;
execv;
execvp;
execve ; 系统调用
自主实现minishell
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/wait.h>
int main(){
//用户界面
while(1){
printf("[san@localhost]$ ");
fflush(stdout);
char cmd[1024] = {0};
if(scanf("%[^\n]%*c",cmd) != 1){
getchar();
}
printf("%s\n",cmd);
char* argv[32];
int argc = 0;
char* ptr = cmd;
//解析输入的命令
while(*ptr != '\0'){
if(!isspace(*ptr)){
argv[argc++] = ptr;
while(!isspace(*ptr)&&*ptr != '\0'){
ptr++;
}
} else{
*ptr = '\0';
ptr++;
}
}
argv[argc] = NULL;
pid_t pid = fork();
if(pid < 0){
return -1;
}else if(pid == 0){
execvp(argv[0],argv);
exit(0);
}
wait(NULL);
}
return 0;
}
封装fork/wait等操作, 编写函数 process_create(pid_t* pid, void* func, void* arg), func回调函数就是子进程执行的入口函数, arg是传递给func回调函数的参数.