Linux中fork系统调用

1. fork系统调用头文件:<unistd.h>;

2. fork系统调用的原型:pid_t fork();

3. fork系统调用的返回值:pid_t是进程描述符类型,本质就是一个int。如果fork函数执行失败,返回一个负数(<0);如果fork调用执行成功,返回两个值:0和所创建子进程的ID。

4. fork系统调用的功能:以当前进程作为父进程创建出一个新的子进程,并且将父进程的所有资源拷贝给子进程,这样子进程作为父进程的一个副本存在。父子进程几乎时完全相同的,但也有不同的如父子进程ID不同。

5. 注意:当fork系统调用成功时,它会返回两个值:一个是0,另一个是所创建的新的子进程的ID(>0)。当fork成功调用后此时有两个数据相同的父子进程,我们可以通过fork的返回值来判断接下来程序是在执行父进程还是子进程。

pid_t pid = fork();
if(pid == 0)
{
      //在子进程中
}
else if(pid > 0)
{
      //在父进程中
}
else
{
     //fork调用失败
}
6. fork调用与文件描述符的关系

前面我们知道当我们使用fork系统调用以当前进程作为父进程创建出了一个子进程,父进程将自己的在fork系统调用之前的所有数据和代码都复制一份给子进程,此时子进程相当于父进程的一个拷贝。对于在fork调用之前打开的文件也一样,也会做一个拷贝将文件描述符复制给子进程,这样父子进程可以同时对一个文件进行操作。但是这种操作是共享式的,父子进程共享这个文件描述符所索引的文件。何谓父子进程共享这个文件呢?举个简单例子说明下

如果一个已经打开的txt文件,里边的内容是一个字符串“abcdefg”。在父进程中读取前两个字符“ab”,此时文件指针指向c。如果在子进程中再次读取两个字符,那么它读取就是“cd”,并且读完后文件指针指向e。这就是父子进程以共享的方式来操作文件。下面我们通过代码说明这个关系:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<iostream>
#include<pthread.h>
#include<fcntl.h>//为了使用O_RD_ONLY
int gb = 10;
using namespace std;
int main()
{
	int fd = open("fork.txt", O_RDONLY);
	if(fd < 0)//文件描述符是一个非负整数:0是stdin的文件描述符,1是stdout的文件描述符,2是stderr的文件描述符
	{
		cout<<"error in open the file!"<<endl;
		exit(1);
	}
	cout<<"文件描述符为:"<<fd<<endl;
	char *c = new char[3];
	int a = 5;
	cout<<"main函数中的进程ID:"<<getpid()<<endl;
	pid_t pid = fork();//fork系统调用的作用是:使用当前进程作为副本创建出一个子进程。它会返回两个值,一个是子进程的ID,一个是0
	if(pid == 0)//在子进程中
	{
		read(fd, c, 2);
		c[2] = '\0';
		cout << "---------------------------------------------"<<endl;
		cout << c << endl;
		gb += 10;
		a += 10;
		cout << "gb = " << gb << ",a = " << a << endl;
		cout << "子进程ID:" << getpid() << ",子进程的父进程ID为:" << getppid() << endl;
		cout << "子进程中pthread_self():" << pthread_self() << endl;//因为两个pthread_self()函数都是在主线程中的,所以两个获取的线程ID相同
	}
	else if(pid > 0)//在当前进程中,也就是父进程中
	{
		read(fd, c, 2);
		c[2] = '\0';
		cout << "--------------------------------------------"<<endl;
		cout << c << endl;
		cout << "gb = " << gb << ",a = " << a << endl;
		cout << "父进程ID:" << getpid() << ",父进程的父进程ID为:" << getppid() << endl;
		cout<<"父进程中pthread_self():"<<pthread_self()<<endl;//因为两个pthread_self()函数都是在主线程中的,所以两个获取的线程ID相同
	}
	else
	{
		cout<<"fork error!"<<endl;
		exit(1);
	}
	close(fd);//关闭文件描述符对应的文件,如果关闭成功返回0,关闭失败返回-1
	return 0;
}
在linux中执行结果:

 

这里我们使用open系统调用打开了一个名为fork.txt的文件,文件中的是一个个字符串。
 (1)文件描述符为3:因为系统中0时stdin的文件描述符,1是stdout的文件描述符,2是stderr的文件描述符。其他的用于索引我们自己打开的文件描述符,每打开一个一个文件就是使用最小的可使用的文件描述符表示。如果再打开一个文件,他的fd是4.

(2)使用getpid()函数可以获取当前进程的ID,使用getppid()可以获取当前进程的父进程的ID,使用pthread_self()可以获取当前线程的ID。

(3)通过结果可以看出我们使用fork创建了子进程并在子进程中对变量gb和a做了修改,但是这个修改并不会影响到父进程中两个变量的值。这是因为fork系统调用将父进程中的变量拷贝一份给子进程中。父子进程中的数据各不相关。

(4)在父进程中使用read系统调用读取文件的前两个字符ab。然后在子进程中再次读取两个字符是cd,而不是ab。这说明父子进程共享同一个文件,它们对文件的操作是同步的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值