一、fork之后父子进程共享文件
打开的文件在fork之后共享文件表。
示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
#define MAJOR(a) (int)((unsigned short)a>>8)
#define MINOR(a) (int)((unsigned short)a & 0xFF)
int filetype(struct stat *buf);
int main(int argc,char* argv[])
{
int infd;
int outfd;
int ret;
infd = open("aa.txt",O_WRONLY);
if ((ret = fork()) > 0)
{
write(infd,"ABC",3);
}
else
{
write(infd,"DEF",3);
}
wait(&ret);
return 0;
}
文件里会输出:ABCDEF字样。
二、fork和vfork
在fork还没实现copy on write之前。Unix设计者很关心fork之后立刻执行exec所造成的地址空间浪费,所以引入了vfork系统调用。
但是vfork有个限制,子进程必须立刻执行_exit或者exec函数。
vfork保证子进程先运行,在子进程调用exec或exit之后父进程才可能被调度运行。子进程没有自己的地址空间,在vfork()返回后子进程直接运行在父进程的栈空间,并使用父进程的内存和数据。
注意:即使fork实现了copy on write,效率也没有vfork高,但是我们不推荐使用vfork,因为
几乎每一个vfork的实现,都或多或少存在一定的问题。
示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.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);
int ret;
int var;
var = 1;
if ((ret = vfork()) > 0)
{
printf("parent start...\n");
printf("var=%d\n",var);
}
else if(ret == 0)
{
sleep(3);
var = 3;
_exit(0);
}
return 0;
}
父进程等待子进程执行exit或者exec,子进程改变了父进程的数据。父进程在3s之后输出:
parent start...
var=3
var=3
三、进程退出方式和atexit
正常退出
- 从main函数返回
- 调用exit
- 调用_exit
异常退出
- 调用abort
- 由信号终止
exit和_exit的区别是_exit是系统调用,而exit是C库调用。exit结束之前会清空缓冲区并且调用终止处理程序,而缓冲区和终止处理程序都术语用户态,所以_exit不会清空缓冲区,也不会调用终止处理程序。
示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void my_exit1()
{
printf("my_exit1...\n");
}
void my_exit2()
{
printf("\nmy_exit2...\n");
}
int main(int argc,char* argv[])
{
atexit(my_exit1);
atexit(my_exit2);
char ch;
ch = getchar();
if (ch == 'a')
{
printf("hello");
exit(0);
}
else
{
printf("hello");
_exit(0);
}
}
输出:
sh@ubuntu:~/sys$ ./a.out
a
hello
my_exit2...
my_exit1...
sh@ubuntu:~/sys$ ./a.out
b
sh@ubuntu:~/sys$