fork 系统调用
系统调用fork() 用于创建一个新的进程
系统调用fork()创建一个新的进程,子进程和父进程共享代码空间,但其拥有不同的数据空间,父子进程可以看成两个同时运行的进程,在fork()后面分开运行
fork()的返回值并不相同,在父进程中fork()的返回值为子进程的ID,而子进程中fork()返回值为0,如果未能创建新的进程,返回一个负值。于是可根据fork()返回值来区分父子进程,并令其执行不同的命令
具体样例
int main(int argc,char* argv[]){
int pid = fork();
if(pid < 0){// 创建新进程失败
printf("创建新进程失败");
}else if(pid == 0){// 在子进程中fork()返回值为0 所以该进程为子进程
printf("我是子进程\n");
}else{
printf("我是父进程\n");
}
}
相同的代码竟然会有两个不同的输出,这是因为实际上是由两个不同的进程在执行该代码,而这两个进程的pid返回值不同,所以会有两个不同的输出。
上面程序的输出顺序并不是固定的,这由CPU调度程序(scheduler)来决定,如果想让子进程先输出,可以在父进程中使用wait
exec系统调用
该系统调用可以让子进程执行与父进程不同的程序
该调用在调用时会从可执行程序中加载代码和静态数据,并覆盖自己的代码段和静态数据,堆。栈及其他内存空间,然后操作系统重执行该程序,并传入argv命令参数
注意:exec系统调用并没有创建新的进程,而是将原来进程中的程序进行替换,注意进行exec系统调用后,原程序被覆盖,exec后的代码不会继续执行
利用fork()和exec()实现I/O重定向
对于重定向中文件描述符的内容请参照上一篇博客。
实例: 实现cat的重定向(默认输入的命令合法为:cat 文件名 (> 文件名) 的形式)
cat: 将文件内容标准输出
int buf[64];
void cat(int fd);
int main(int argc,char* argv[]){
if(argc < 2){
cat(0);
exit(0);
}
if(argc < 3){//不考虑重定向部分
int fd = open(argv[1],O_RDONLY);//打开要读出的文件,并返回其文件描述符
cat(fd);
exit(0);
}
int pid = fork();
if(pid == 0){
close(STDOUT_FILENO);//关闭标准输出
open(argv[3],O_WRONLY);//此时标准输出关闭,最小的文件描述符为1,此时新open的文件会分配到最小的文件描述符1
char *myargs[3];// 建立新的命令参数
myargs[0] = strdup(argv[0]); //strdup会动态分配内存并将该字符串复制到新分配的内存中
myargs[1] = strdup(argv[1]);
myargs[2] = NULL;
execvp(myargs[0],myargs); // 新加载的程序文件名 新的命令行参数列表
}
exit(0);
}
在上述例子中,exec重新调用了cat,事实上exec可以调用其他不同的程序,从而使得子进程,父进程分别执行不同的程序.