前言
fork是什么?克隆当前的进程,然后创建一个子进程。本文分几个验证实例代码,主要是为解决验证一些小问题。
一 fork与文件描述符
fork之前打开一个文件的测试。
问题:fork之后,父进程关闭文件,子进程是否还可以正常写文件?
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd;
char buf[100];
int count = 0;
int pid;
fd = open("hello.txt",O_RDWR|O_CREAT,0666);
if(fd < 0){
perror("open");
return -1;
}
printf("open ok\n");
pid = fork();
if(pid == -1){
perror("fork");
exit(-1);
}
if(pid > 0){
printf("parent:pid = %d\n",getpid());
close(fd);
}else{
while(1){
sprintf(buf,"count = %d\n",count++);
write(fd,buf,strlen(buf));
sleep(1);
}
}
while(1)
sleep(1);
return 0;
}
这个程序得出的结果是,子进程会不停的向文件中写内容,即便父进程关闭了fd。这说明,fork执行以后,子进程继承了父进程的资源。并且继承了文件描述符,子进程与父进程在fork以后,就是两个不同的进程了。
这时,杀死父进程,子进程将被系统进程接管。
杀死子进程呢?子进程将变成僵尸进程。如何处理僵尸进程呢?暂时先不讨论这个问题。
二 fork与线程
fork之前创建一个线程。
问题:fork之后,子进程是否拥有一个该线程的复制?
测试实例:fork.c
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void * mythread(void *arg)
{
while(1){
printf("pid = %d\n",getpid());
sleep(1);
}
return NULL;
}
int main()
{
int fd;
char buf[100];
int count = 0;
int pid;
pthread_t t;
fd = open("hello.txt",O_RDWR|O_CREAT,0666);
if(fd < 0){
perror("open");
return -1;
}
printf("open ok\n");
pthread_create(&t,NULL,mythread,NULL);
pid = fork();
if(pid == -1){
perror("fork");
exit(-1);
}
if(pid > 0){
printf("parent:pid = %d\n",getpid());
close(fd);
}else{
while(1){
sprintf(buf,"count = %d\n",count++);
write(fd,buf,strlen(buf));
sleep(1);
}
}
while(1)
sleep(1);
return 0;
}
编译
gcc fork.c -pthread
测试结果:
lkmao@ubuntu:~/01$ ./a.out
open ok
pid = 124353
parent:pid = 124353
child:pid = 124355
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
pid = 124353
执行pstree -p命令:
{a.out}124354,就是创建的线程,它只有一个。
三 fork与malloc
fork之前使用malloc分配内存。fork之后,父进程free这块内存,请问,子进程是否还有该内存的使用权?
一句话:每个进程都拥有,且独立使用4GB的虚拟内存空间。还像是这么说的。
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void * mythread(void *arg)
{
while(1){
printf("pid = %d\n",getpid());
sleep(1);
}
return NULL;
}
int main()
{
int fd;
char* buf;
int count = 0;
int pid;
pthread_t t;
fd = open("hello.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
if(fd < 0){
perror("open");
return -1;
}
printf("open ok\n");
buf = malloc(100);
pthread_create(&t,NULL,mythread,NULL);
pid = fork();
if(pid == -1){
perror("fork");
exit(-1);
}
if(pid > 0){
printf("parent:pid = %d\n",getpid());
free(buf);
close(fd);
}else{
printf("child:pid = %d\n",getpid());
while(1){
sprintf(buf,"count = %d\n",count++);
write(fd,buf,strlen(buf));
sleep(1);
}
}
while(1)
sleep(1);
return 0;
}
这个测试结果和实例1一样。
这样验证可能还是不太好,从新写验证代码,fork之前对buf赋值 "count = 0",fork之后,父进程修改buf。然后,子进程等待1秒,然后子进程打印buf,思考子进程打印的buf是什么?不用想的看结果吧。
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main()
{
char* buf;
int count = 0;
int pid;
pthread_t t;
buf = malloc(100);
sprintf(buf,"count = %d\n",count++);
pid = fork();
if(pid == -1){
perror("fork");
exit(-1);
}
if(pid > 0){
printf("buf = %p\n",buf);
printf("parent:pid = %d\n",getpid());
sprintf(buf,"pid = %d\n",getpid());
printf("parent buf:%s\n",buf);
}else{
sleep(1);
printf("buf = %p\n",buf);
printf("child:pid = %d\n",getpid());
printf("child buf:%s\n",buf);
}
while(1)
sleep(1);
return 0;
}
测试结果:虽然父子进程的buf地址相同,但是父子进程的buf中的内容,是完全不同的。这就是为什么说,每个进程的虚拟地址空间独立的原因吧。
lkmao@ubuntu:~/01$ gcc fork.c
lkmao@ubuntu:~/01$ ./a.out
buf = 0xe01010
parent:pid = 126902
parent buf:pid = 126902
buf = 0xe01010
child:pid = 126903
child buf:count = 0
小结
暂时想到这几个问题,关于如何处理僵尸进程呢?这个问题,下次研究。