测试代码1:
# include <stdio.h>
# include <error.h>
# include <sys/types.h>
# include <string.h>
int main(int argc, char *argv[]){
char s[] = "hello\n";
write(1, s, strlen(s));
printf("world\n");
pid_t pid;
if((pid = fork()) < 0) perror("fork error");
else if(pid == 0) printf("i am son %d %d\n",getpid(), getppid());
else printf("i am father %d %d %d\n",getpid(), getppid(), pid);
return 0;
}
$ gcc unix.c -o unix
$ ./unix
hello
world
i am father 4220 2991 4221
i am son 4221 4220
$ ./unix 1>tmp.txt
$ cat tmp.txt
hello
world
i am father 4237 2991 4238
world
i am son 4238 4237
第一次运行结果hello world各输出一次。
第二次运行结果world输出了2次,原因是将输出重定向到文件,由于write是非缓存IO,只输出一次;而printf是标准IO,如果输出到终端设备是行缓冲的,也就是输出一行就会就会冲洗缓冲区,而输出到文件就变成全缓冲,即填满缓冲区才冲洗。fork函数之后子进程复制父进程的数据空间、堆栈,包括缓冲区的未冲洗的数据,因此world还会再输出一次到文件。另外一个问题就是文件共享问题,子进程是将父进程的文件描述符也复制一份的,也就意味着两者的进程表项的fd表共享一个文件表项,进而共享一个文件偏移量,因此两个进程写数据到文件的时候才不会互相覆盖。
测试代码2:
//unix2.c
# include <stdio.h>
int main(int argc, int *argv[]){
printf("I am the new. My paras are \n");
for(int i=0; i<argc; ++i) printf("%s\n",argv[i]);
extern char **environ;
for(char **ptr = environ; *ptr!=0; ++ptr){
printf("%s\n",*ptr);
}
return 0;
}
$ gcc unix2.c -o unix2
# include <stdio.h>
//unix.c
# include <error.h>
# include <sys/types.h>
# include <string.h>
char *env_init[] ={"USER=KK", "PATH=/etc", NULL};
int main(int argc, char *argv[]){
pid_t pid;
if((pid = fork()) < 0) perror("fork error");
else if(pid == 0){
if(execle("/home/junior/unixt/unix2", "my arg1", "myarg2", (char *)0, env_init) < 0)
perror("exec error");
}
if(waitpid(pid, NULL, 0) < 0) perror("waitpid error");
if((pid = fork()) < 0) perror("fork error");
else if(pid == 0){
if(execlp("./unix2", "my arg1", "myarg2", (char *)0) < 0)
perror("exec error");
}
return 0;
}
$ gcc unix.c -o unix
$ ./unix
I am the new. My paras are
my arg1
myarg2
USER=KK
PATH=/etc
I am the new. My paras are
my arg1
myarg2
XDG_VTNR=7
MANPATH=/home/junior/gnuplot/share/man/man1:
XDG_SESSION_ID=c2
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/junior
CLUTTER_IM_MODULE=xim
SESSION=ubuntu
GPG_AGENT_INFO=/home/junior/.gnupg/S.gpg-agent:0:1
TERM=xterm-256color
VTE_VERSION=4205
XDG_MENU_PREFIX=gnome-
SHELL=/bin/bash
QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1...
代码在fork之后调用exec函数将子进程替换成其他程序,这里用到execle和execlp,l代表参数以list的形式传入,以NULL结束参数;e表示定义新的环境表,p表示复制父进程的环境表,environ指针是用来查看当前进程的环境表的。