(1) 写个程序调用 fork()
。调用 fork()
之前,主程序使用并设置变量x的值。子程序中x的值是多少?同时在父程序和子程序中修改x的值会发生什么?
// p1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int x = 0;
printf("father x is %d\n", x);
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(-1);
} else if (rc == 0) {
printf("child x is %d\n", x); // 子进程
x = 10;
printf("child x has changed to %d\n", x);
} else { // 父进程
x = 100;
printf("father x has changed to %d\n", x);
}
exit(1);
return 0;
}
可以看到,父进程和子进程的x初值均为0,并在各自的进程内变化为100和10,变量互不影响。
(2) 写个进程用 open()
打开一个文件,调用 fork()
创造新进程。父进程和子进程都能通过open()
访问该文件么?它们同时写入文件时会发生什么?
函数 | 参数 |
---|---|
open | O_RDONLY只读模式、O_WRONLY只写模式、O_RDWR读写模式 |
read(int fd, void *buf, size_t count) | 读取文件名fd,读入内存空间名buff,读入字节数count |
write (int fd,const void * buf,size_t count) | 写入文件名fd、读取内存空间名buff、读取字节数count |
// p2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main() {
int fd = open("./p2.rtf", O_RDWR);
char buff[20];
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(-1);
} else if (rc == 0) {
read(fd,buff,20);
printf("child process read:%s\n", buff);
write(fd, "child process write ", 20);
} else {
read(fd,buff,20);
printf("father process read:%s\n", buff);
write(fd, "father process write\n", 20);
}
exit(1);
return 0;
}
可以看到,只有父进程成功读取文件的内容,但父进程和子进程都成功地写入文件。
(3) 写另一使用 fork()
的程序。子进程应该打印"hello";父进程应该打印"goodbye"。程序保证先打印子进程的内容,并且不在父进程使用 wait()
// p3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(-1);
} else if (rc == 0) { // 第1个子进程
printf("hello\n");
} else {
int id = fork(); // 第2个子进程
if (id == 0) printf("goodbye\n");
}
exit(1);
return 0;
}
主程序main()调用fork()创建子进程1输出hello
,然后父进程内再次调用fork()创建子进程2输出goodbye
。父进程和子进程同时执行,从进程树的角度看,子进程2比子进程1处于更深位置,执行时间更长,从而保证先输出hello
。
(4) 写个程序调用fork()
及exec()
函数簇重载程序 /bin/ls
,并分析exec()
函数簇区别。
#include <stdio.h> // fprintf printf stderr
#include <stdlib.h> // exit()
#include <unistd.h> // fork() execvp()
#include <string.h> // strdup()
#include <fcntl.h> // file control options
int main(int argc, char *argv[]) {
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed");
exit(-1);
} else if (rc == 0) {
printf("child process called\n");
char *myargs[2];
myargs[0] = strdup("ls"); // program:"ls"
myargs[1] = NULL; // mark end of array
execvp(myargs[0], myargs);
printf("this shouldn't print out");
} else {
int wc = wait(NULL);
printf("father process called\n");
}
return 0;
}
成功调用fork()
创建子进程,并运行ls
程序显示当前桌面工作目录下的文件。
(5)(6) 写程序在父进程调用wait()
会返回什么?如果在子进程中调用wait()
会发生什么?如何使用waitpid()
使其发挥与wait()
的作用?
父进程调用wait()
返回子进程的PID,子进程调用wait()
,因为没有可以等待结束的进程,所有出错返回-1。waitpid()
的函数原型为waitpid(pid_t pid,int *status,int options)
,设定pid为-1,options为0,则waitpid()
函数就完全退化成了wait()
函数。
(7) 写程序创建子进程,在子进程中关闭标准输出STDOUT_FILENO
会对printf()
有什么影响?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
close(STDOUT_FILENO);
printf("child process called\n");
} else {
printf("father process called\n");
}
return 0;
}
可以看出只有父进程的printf()
语句得到输出,而子进程的printf()
语句因为关闭STDOUT_FILENO
得不到输出。
(8) 写程序创建两个子进程,使用pipe()
将一个进程的标准输出作为另一个进程的标准输入。
学完管道相关知识回来。。。