本博文讲解的是关于进程的创建;首先我们要先知道什么是进程和进程的一些知识
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 <unistd.h>
pid_t fork(void); //无需传递参数
函数返回值
成功时,如果在父进程中,返回值将大于0
成功时,如果在子进程中,返回值将等于0
失败时,在父进程中返回-1
下面是关于创建进程的代码
/*
*关于fork函数的使用
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
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运行结果为:
在16.04下运行结果为:
按照理论上应该是系统在每一个进程执行完之后,终端会打印一个命令行,但是在16.04上面不会;,可能是版本之间的区别吧,CPU运行速度比较快,在16.04上父进程还没被杀死子进程就已经执行结束了
关于验证两个进程并发的代码:
/*
*关于fork函数的使用
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
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()函数小结:
1.当进程被fork()函数创建出来之后,子进程会复制父进程里面的几乎所有代码到自己的进程里面(除了进程ID号和父进程ID号以及fork函数的返回值)
2.进程创建出来后,子进程会继承父进程的执行位置,
3.在fork创建出子进程后,父进程会和子进程一起并发执行自己的代码
4.当代码中有输出代码时,谁先抢占到终端的输出屏幕时就先输出谁的代码
================================================
同时进程创建我们还能使用另一个函数:vfork()
函数头文件:
#include <sys/types.h>
#include <unistd.h>
函数原型:
pid_t vfork(void);
函数作用:
(1)与fork()函数的一样无需传递,会继承了父进程的执行位置;
(2)vfork函数创建的子进程将会与父进程共享一块内存空间
(3)只不过vfork()创建后规定先执行子进程,并且需要子进程运行结束后加上一个退出函数
注:子进程执行完必须退出子进程,否则子进程一直不退出,父进程则一直在等待子进程退出,因此会导致出现段错误
验证代码:
/*
*vfork函数使用
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
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;
}
运行结果:
运行过程:先执行子进程代码,睡眠两秒后,退出子进程再去执行父进程的代码
如果没有退出子进程的话,运行将会出现段错误,并且不执行父进程的代码
验证代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
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函数是与父进程共享同一块内存空间
================================================