标签:
这节主要介绍,父子进程共享文件、fork基于的copy on write、exit(0)与_exit(0)的区别、atexit()终止处理程序。
首先父子进程共享文件:
直接献上一个例子:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0)
int main(int argc, char *argv[])
{
signal(SIGCHLD, SIG_IGN);
printf("before fork pid = %d\n", getpid());
int fd;
fd = open("test.txt", O_WRONLY); //在父进程中打开一个文件
if (fd == -1)
ERR_EXIT("open error");
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid > 0)
{
printf("this is parent pid=%d childpid=%d\n", getpid(), pid);
write(fd, "parent", 6); //从父进程中向文件写
sleep(3);
}
else if (pid == 0)
{
printf("this is child pid=%d parentpid=%d\n", getpid(), getppid());
write(fd, "child", 5); //从子进程中向文件写
}
return 0;
}
可以看出,在子进程中不用重新打开文件,直接利用父进程中的文件描述符就可以对文件进行操作,这里值得注意的是有可能父进程先写进去子进程再写的时候直接把
父进程写的内容给覆盖了,这是犹豫子进程写的时候父进程可能已经结束,这是用sleep控制一下会看出效果,这个大家自己动手试一试。
fork的copy on write特性:
意思就是父子进程各自都有自己的地址空间,但是都共享一些初始未变的东西,当子进程中有改变的时候就会拷贝一份放到自己的地址空间中去,看例子:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0)
int gval = 100;
int main(int argc, char *argv[])
{
signal(SIGCHLD, SIG_IGN);
printf("before fork pid = %d\n", getpid());
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid > 0)
{
sleep(1);
printf("this is parent pid=%d childpid=%d gval=%d\n", getpid(), pid, gval);
sleep(3);
}
else if (pid == 0)
{
gval++;
printf("this is child pid=%d parentpid=%d gval=%d\n", getpid(), getppid(), gval);
}
return 0;
}
打印的结果:父进程还是100而子进程是101。
exit(0)与_exit(0)的区别:
1、exit(0)是C函数库提供的,而_exit(0)是linux系统的系统调用。
2、

这个就是执行时候的区别,_exit(0)会直接去到内核中去,而exit(0)会调用终止程序和清除i/o缓冲。
int main(int argc, char *argv[])
{
printf("hello world");
//fflush(stdout);
//_exit(0);
exit(0);
}
int main(int argc, char *argv[])
{
printf("hello world");
//fflush(stdout);
_exit(0);
//exit(0);
}
int main(int argc, char *argv[])
{
printf("hello world\n");
//fflush(stdout);
_exit(0);
//exit(0);
}
int main(int argc, char *argv[])
{
printf("hello world");
fflush(stdout);
_exit(0);
//exit(0);
}
可以看出请没清缓冲去的区别,这里\n和fflush都是有清的功能,只是为了让大家了解一下。
下面是终止处理程序,简单了解一下:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0)
void my_exit1(void)
{
printf("my exit1 ...\n");
}
void my_exit2(void)
{
printf("my exit2 ...\n");
}
int main(int argc, char *argv[])
{
//下面是两次安装
atexit(my_exit1);
atexit(my_exit2);
_exit(0);
}
可以看出终止处理程序的调用次序和安装次序正好相反,了解了解即可。
最后给出一个有意思的小程序,供大家分享一下父子进程的运行流程:
int main(int argc, char *argv[])
{
fork();
fork();
fork();
printf("ok\n");
return 0;
}
运行一下看看能打印多少个OK,自己动手画一下运行线图可以理解清楚。
答案是:8个。
标签:
原文地址:http://www.cnblogs.com/DamonBlog/p/4373495.html