fork系统调用

1.fork系统调用


  pid_t fork(void);

  该函数每次调用都返回两次,在父进程中返回的是子进程的PID,在子进程中返回0。失败返回-1,并设置errno。(因为父进程可能需要根据返回值来记录子进程的id,而子进程只需要根据返回值0来判断是否创建成功)

  fork函数复制当前进程,在内核进程表中创建一个新的表项。

  子进程代码和父进程完全相同,同时它还会复制父进程的数据(堆数据、栈数据和静态数据)。数据的复制采用的是写时复制,即只有在任一进程(父进程或者子进程)对数据执行了写操作时,复制才会发生。

  此外创建子进程后,父进程打开的文件描述符(在fork之前打开的文件)在子进程中也是打开的,并且共享文件读写偏移量,且文件描述符的引用计数加1。

2.问题


  问题1:如果在fork之前进行了char *p = malloc(1024)操作,则子进程也继承这部分内存空间,因为两个进程有各自的虚拟空间,所以两个进程的p的地址一样,但是进行读写操作时会对应到不同的物理地址。

      如果在fork之前进行了char *p = malloc(1024)操作,并且执行了strcpy(p,"hello");,所以如果两个进程读这部分物理内存数据时,此时物理内存只有一份数据,而如果一个进程有写操作时,会复制一份到当前进程的物理内存(写时复制)。

  问题2:子进程的执行位置就是fork()之后的位置,这是因为子进程继承了父进程的PC程序计数器。

  问题3:在fork之前执行fp = fopen("abc.dat", "w");则父子进程共享文件描述符和文件偏移量,如果子进程写入数据,父进程要读取的话需要调用lseek函数。而如果是在fork之后打开文件,则此时父子进程不共享文件描述符。

  问题4:下面的例子很简单,第一个fork之后,变为两个进程,之后这两个进程都执行自己的fork,因此最后变为4个进程。

	//[1]给出如下C程序,在linux下使用gcc编译,给出输出结果。				
	int main()
	{
		pid_t pid1, pid2;
	 
		pid1 = fork();
		pid2 = fork();
	 
		printf("pid1:%d, pid2:%d\n", pid1, pid2);
		return 0;
	}

	第一个fork之后:			F					C1
	第二个fork之后:		F		C2			C1		CC1
	所以最后有4个进程,	  100,200	100,0		0,300	0,0		数字代表当前进程两次fork的返回值


	//[2]给出如下C程序,在linux下使用gcc编译,给出输出结果。	
	int main(void)
	{
	   int i;

	   for(i=0; i<2; i++){
	      fork();
	      printf("-\n");
	   }
	
	   return 0;
	}
	
	这个和上面的是一样的,最后也是有4个进程。会输出6个“-”。
	第一个fork之后:			  F('-')					  C1('-')
	第二个fork之后:		F('-')		C2('-')			C1('-')		CC1('-')

posted on 2019-02-26 16:35  能量星星  阅读(728)  评论(0编辑  收藏  举报

导航