
进程控制主要分为三个方面,分别是:子进程的创建,进程等待,进程替换
fork()系统接口创建子进程后,操作系统会为子进程创建独立的PCB结构体和虚拟地址空间mm_struct,因此父子进程之间具有互相独立性fork()函数之后:
#include
#include
#include
int g_val = 0;
int main(int argc,const char * argv[])
{
//创建子进程
pid_t id = fork();
if(id < 0)
{
//创建子进程失败,退出主函数
perror("fork");
return 0;
}
else if(id == 0)
{
//子进程执行流
//子进程对变量g_val进行修改,引发写时拷贝
g_val=100;
printf("childProcess[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else
{
//父进程的执行流
//父进程先休眠3秒,让子进程先完成g_val变量的写入
sleep(3);
printf("parentProcess[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}



int waitpid(int pid, int *status, int options);
形参int pid:
形参int *status:用于记录进程退出码和退出信号的输出型参数
形参int options表示进程等待的方式:主要分为阻塞等待和非阻塞等待两大类:
option为0时:进程执行阻塞等待,此时进程会进入阻塞状态(PCB退出运行队列,进入阻塞队列),直到其所等待的子进程退出,该进程才会重新进入运行状态读取子进程的退出信息option为非零时(比如使用系统宏WNOHANG):进程执行非阻塞等待, 此时进程会尝试读取其子进程的退出信息,若没能读取到子进程的退出信息,则waitpid系统接口立即返回0返回值int:若waitpid系统接口读取到子进程的退出信息,返回子进程的pid,若waitpid执行过程中出现错误,则返回-1
#include
#include
#include
#include
int main()
{
int pid = 0;
//创建子进程
pid = fork();
if(pid == -1)
{
//子进程创建失败
printf("fork failed\n");
return -1;
}
else if(pid == 0)
{
//子进程的代码执行流
int cnt = 5;
while(cnt--)
{
sleep(1);
printf("child process running\n");
}
exit(11);
}
else
{
//父进程的代码执行流
//非阻塞等待子进程
int status = 0;
bool quit = 0;
while(quit == 0)
{
//循环非阻塞等待子进程
int res = waitpid(pid,&status,WNOHANG);
if(res > 0)
{
//子进程已退出
printf("waiting pid success,chilProc exit,退出码:%d\n",WEXITSTATUS(status));
quit = 1;
}
else if(res == 0)
{
//子进程还未退出
printf("waiting pid success,childProc still running\n");
}
else
{
//等待发生错误
printf("waiting pid failed\n");
}
sleep(1);
}
}
return 0;
}

main函数命令行参数)

PCB和虚拟内存结构体不变)
const char*path:表示将要替换现有代码段的目标可执行程序的完整路径const char*file:表示将要替换现有代码段的目标可执行程序的文件名,其系统路径由环境变量PATH决定const char*arg,...:表示传给新代码段main函数命令行参数的字符串,...表示可变参数列表,可以传入多个字符串,最后一个字符串需传入NULLchar *const argv[]:表示传给新代码段main函数命令行参数的字符串数组,数组中最后一个字符串需传入NULLcahr*const envp[]:表示传递给新代码段的环境变量字符串数组exec系列系统接口会返回-1exec*系列系统接口在Linux系统中充当着指令集和数据加载器的角色shell进程的运行原理:shell进程接收到用户输入的指令后,对指令进行格式化处理,然后创建子进程,子进程通过exec系列系统接口将自身替换成系统命令并执行以响应用户需求,shell进程的这种运行机制保证了自身的进程安全(子进程出现错误不会影响到父进程的运行)
#include
#include
#include
#include
#include
#include
//用户输入的命令行的最大长度
#define CStrLen 1024
//解析命令行得到的格式化字符串数组
#define SStrLen 50
//命令行字符串
char CommStr[CStrLen];
//格式化命令行字符串数组
char* StdStr[SStrLen];
//命令行分隔符
#define Sep " "
//操作系统配置的环境变量
extern char ** environ;
int main()
{
while(1)
{
printf("[我的命令行解释器 myshell]$ ");
fflush(stdout);
memset(CommStr,'\0',sizeof StdStr);
//获取用户输入命令
if(fgets(CommStr,sizeof CommStr,stdin)== NULL)
{
continue;
}
CommStr[strlen(CommStr)-1] = '\0';
StdStr[0] = strtok(CommStr,Sep);
//根据空格对用户输入的字符串进行分割并存入StdStr字符串数组中
int i = 1;
while(StdStr[i++] = strtok(NULL,Sep));
//部分命令(比如cd命令)需要由shell进程自己来执行
if(strcmp(StdStr[0],"cd")== 0)
{
//用chdir函数改变shell进程的工作路径
if(StdStr[1] != NULL)
{
chdir(StdStr[1]);
}
continue;
}
//shell创建子进程来执行系统命令
int pid = fork();
if(pid == 0)
{
//printf("shell的子进程执行系统命令:\n");
execvp(StdStr[0],StdStr);
printf("-mybash: %s: command execute failed\n",StdStr[0]);
exit(-1);
}
else
{
int status;
//父进程进行阻塞等待,等待子进程执行完系统命令结束并获取其退出码
int waitres = waitpid(pid,&status,0);
if(waitres == -1)
{
printf("waitchild process failed\n");
}
}
}
return 0;
}

