12进程

这节主要介绍,父子进程共享文件、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个。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。