在linux里面常用的调度算法是时间片轮转法,即每一个进程分为很多的块,每一块都只能占用CPU固定的时间,当时间到,这个进程就必须放弃对CPU的使用权限。然后CPU去执行下一个进程。
在使用fork()函数创建一个子进程的时候,父进程和子进程执行的先后顺序是不确定的,所以子进程和父进程执行行为先后次序是不确定的。但是在除开使用fork()函数的同时也可以使用vfork()来创建进程,vfork()在创建进程的时候,必须是在子进程执行完之后再去执行父进程。在fork()创建进程的时候采用的是写实拷贝技术,但是使用vfork()函数的时候即使写时也不拷贝,即在改变子进程的同时也改变了父进程的数据。也因此,在使用vfork()创建进程的时候会出现一些意想不到的事情。
进程等待:
必要性:在使用多进程的时候,父进程需要知道子进程的退出信息,同时也需要回收子进程的资源,以及子进程的死亡信息。
进程等待的方法:
pid_t wait(int * status);
如果wait函数正常返回,则返回死亡子进程的ID,其中status里面保存的是子进程退出的基本信息。如果wait函数调用失败则返回-1。
例如:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
printf("begin fork()!\n");
pid = fork();
if(pid == -1)
perror("fork():");
if(pid == 0)
{
printf("I'm child!\n");
sleep(5);
}
else
{
int status;
wait(&status);
printf("wait end!\n");
}
return 0;
}
在输出I'm child!
之后睡眠5秒之后再输出wait end!
在这个程序里面,当使用fork()函数之后,父进程和子进程同时存在,但是在父进程里面使用了wait函数,这时候在子进程没有退出之前,父进程一直在wait函数地方等待,直到子进程在执行完之后再退出,这时候wait函数返回,父进程开始执行下面的代码。
pid_t waitpid(pid_t pid,int* status,int pation);
pid
:
- pid = -1
表示任意一个子进程退出,则返回
- pid >0
表示等待和pid相同的ID进程退出则返回。
status
:
WIFEXITED
: 判断自己成是否是正常退出WEXITSTATUS
:如果返回statu>0,则提取子进程的退出码
pation
:
- WNOHANG
:如果指定子进程没有返回,则返回0,如果正常返回则返回指定子进程的ID。在程序执行的过程中不等待。
例如:
int main()
{
pid_t r;
pid_t pid;
int status;
pid = fork();
if(pid == -1)
perror("fork():");
else if(pid == 0)
{
printf("hehe\n");
}
else
{
r = wait(&status);
printf("%d\n",WEXITSTATUS(status));
}
}
waitpid函数是在指定子进程退出之后waitpid函数在返回,使用waitpid函数就可以实现指定进程死亡之后,在执行父进程。
在子进程没有执行结束,调用wait/waitpid函数会处于阻塞状态。若子进程正常返回,则wait/waitpid函数正常返回,若不存在子进程或者指定子进程,则wait/waitpid函数立即报错。
若果子进程存在并且子进程退出,则wait函数正常返回,回收子进程的资源,获得子进程的退出信息。
若子进程处于运行状态,则wait函数处于阻塞状态,等待子进程退出。
若子进程不存在,wait函数立即报错。
利用进程等待实现myshell:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<ctype.h>
#include<string.h>
void do_action (char* argv[])
{
if(fork() == 0)
execvp(argv[0],argv);
else
wait(NULL);
}
void do_pose(char *buf) //将输入的字符串拆分
{
int i=0;
int status = 0;
char * argv[8];
int argc = 0;
for(;buf[i] != '\0';i++)
{
if(status == 0 && !isspace(buf[i]))
{
argv[argc++] = buf + i;
status = 1;
}
else if(isspace(buf[i]))
{
buf[i] = 0;
status = 0;
}
}
argv[argc] = NULL;
do_action(argv);
}
int main()
{
char buf[1024];
while(1)
{
printf(">:");
scanf("%[^\n]%*c",buf);
if(strcmp(buf,"exit")==0)
exit(0);
do_pose(buf);
}
}