多进程之创建子进程fork,vfork函数

本博文讲解的是关于进程的创建;首先我们要先知道什么是进程和进程的一些知识
1.进程:是一个正在运行时的程序,系统会给这个程序分配一些系统资源,例如:内存,管理文件的结构体等。。。

2.程序:是由编译器编译后生成的可执行文件

3.所有进程都是由一个进程ID号为 0 的祖先进程创建出来的

4.一个进程里面可以包含多个线程,一个进程中的所有线程间共用该进程的系统资源

5.进程是系统管理分配资源的最小单位

6.线程是系统调度的最小单位

,

7.如果父进程在创建子进程出来后就先运行结束了,子进程就会失去它原来的父进程,系统就会找一个进程来给这个子进程做父进程

8.当进程加入了sleep()函数,该进程将会进入休眠状态,CPU就会先处理其他进程,直到该进程结束休眠状态

9.创建进程可以不断地递归创建(创建子进程,子进程在创建孙子进程)直至pid被分配完为止

10.关于管理进程的结构体:stak_list在这个路径下:
/usr/src/linux-headers-4.15.0-111/include/linux/sched

这个路径下包括了进程管理的一些头文件

关于fork()函数:
函数作用:

NAME
fork - create a child process //创建一个子进程


头文件与函数原型:

#include
pid_t fork(void); //无需传递参数

函数返回值

成功时,如果在父进程中,返回值将大于0

成功时,如果在子进程中,返回值将等于0

失败时,在父进程中返回-1

多进程之创建子进程fork,vfork函数_第1张图片

下面是关于创建进程的代码
/*
 *关于fork函数的使用
 */

#include 
#include 
#include 

int main()
{
	//创建一个子进程
	pid_t id = fork();
	
printf("sss%d\n",id);//这行代码会被执行两次
	//如果创建失败
	if(id<0)
	{
		perror("fork failed");
		return -1;
	}

	//如果是子进程
	else if(id==0)
	{
		printf("i am child\n");
		printf("child:%d\n",getpid());
		printf("child:%d\n",getppid());
	}

	//如果是父进程
	else if(id >0)
	{
		printf("i am parent\n");
		printf("parent:%d\n",getpid());
		printf("parent:%d\n",getppid());
	}

//这行代码会被执行两遍
printf("ssss:%d\n",__LINE__);
	return 0;
}



这个代码在18.04运行结果为:

多进程之创建子进程fork,vfork函数_第2张图片


在16.04下运行结果为:

多进程之创建子进程fork,vfork函数_第3张图片


按照理论上应该是系统在每一个进程执行完之后,终端会打印一个命令行,但是在16.04上面不会;,可能是版本之间的区别吧,CPU运行速度比较快,在16.04上父进程还没被杀死子进程就已经执行结束了


关于验证两个进程并发的代码:
/*
 *关于fork函数的使用
 */

#include 
#include 
#include 

int main()
{
	//创建一个子进程
	pid_t id = fork();
	
printf("sss%d\n",id);//这行代码会被执行两次
	//如果创建失败
	if(id<0)
	{
		perror("fork failed");
		return -1;
	}

	//如果是子进程,打印26字母
	else if(id==0)
	{
		for(int i=0;i<26;i++)
		{
			printf("%c\n",'a'+i);
			sleep(1);
		}

	
	}

	//如果是父进程,打印0-10
	else if(id >0)
	{
		for(int i=0;i<10;i++)
		{
			printf("%d\n",i);
			sleep(1);
		}
	}

	return 0;
}


代码执行结果为:

多进程之创建子进程fork,vfork函数_第4张图片
多进程之创建子进程fork,vfork函数_第5张图片

因为在每次打印都加了一个睡眠一秒,加上两个进程是并发的,因此出现了前十个字母与前十个数字交替输出的情况


fork()函数小结:

1.当进程被fork()函数创建出来之后,子进程会复制父进程里面的几乎所有代码到自己的进程里面(除了进程ID号和父进程ID号以及fork函数的返回值)


2.进程创建出来后,子进程会继承父进程的执行位置,


3.在fork创建出子进程后,父进程会和子进程一起并发执行自己的代码


4.当代码中有输出代码时,谁先抢占到终端的输出屏幕时就先输出谁的代码



================================================



同时进程创建我们还能使用另一个函数:vfork()


函数头文件:

#include
#include

函数原型:

pid_t vfork(void);

函数作用:

(1)与fork()函数的一样无需传递,会继承了父进程的执行位置;
(2)vfork函数创建的子进程将会与父进程共享一块内存空间
(3)只不过vfork()创建后规定先执行子进程,并且需要子进程运行结束后加上一个退出函数



注:子进程执行完必须退出子进程,否则子进程一直不退出,父进程则一直在等待子进程退出,因此会导致出现段错误

验证代码:

/*
 *vfork函数使用
 */

#include 
#include 
#include 

int main()
{
	//创建子进程
	pid_t pid = vfork();

	//创建失败
	if(pid<0)
	{
		perror("creat failed");
		return -1;
	}

	//子进程
	else if(pid == 0)
	{
		printf("i am child\n");
		sleep(2);
		//退出子进程
		_exit(0);
	}

	//父进程
	else if(pid >0)
	{
		printf("i am parent\n");
	}

	return 0;
}

运行结果:


vfork使用

运行过程:先执行子进程代码,睡眠两秒后,退出子进程再去执行父进程的代码

如果没有退出子进程的话,运行将会出现段错误,并且不执行父进程的代码

验证代码:

#include 
#include 
#include 

int main()
{
	//创建子进程
	pid_t pid = vfork();

	//创建失败
	if(pid<0)
	{
		perror("creat failed");
		return -1;
	}

	//子进程
	else if(pid == 0)
	{
		printf("i am child\n");
		sleep(2);
		//退出子进程
		//_exit(0);
	}

	//父进程
	else if(pid >0)
	{
		printf("i am parent\n");
	}

	return 0;
}

运行结果:
在这里插入图片描述

将会出现段错误,因为子进程没有退出,代码无法正常继续执行下去,因此产生了段错误

总结:
1.fork()函数与vfork()函数其实用法差不多且返回值都是一样的,都是创建一个子进程
2.fork()函数无法确定先执行子进程的代码还是父进程的代码,但是vfork()函数中规定了先执行子进程的代码,直至子进程退出为止
3.使用vfork()函数时必须记得要加上一个进程退出函数,否则将会产生段错误
4.fork函数是复制一块父进程大小的内存空间,但是vfork函数是与父进程共享同一块内存空间


================================================

这些都是关于我个人的一些理解,包括图也都是自己画的;如果有什么地方写错或者画错了麻烦告知一下,真的非常感谢

你可能感兴趣的:(操作系统,多进程,c语言)