进程控制(一)
进程控制(一)
主要介绍两个方面的内容:
-
进程的基本概念
-
Linux下进程控制的相关函数调用(fork和vfork)
进程的基本概念
要理解进程的基本概念,首先要理解
Linux是一个多用户多任务的操作系统;
多用户:是指多个用户可以同时使用一台计算机
多任务:Cpu的运行时间分为多个时间片, 每一个任务执行一个时间片,直到时间片所标注的时间点,它都必须退出cpu资源,让其他任务获得cpu资源执行,直到某个任务全部执行完,这个任务才会从cpu任务队列中退出。(即Linux使用分时管理的方法使所有任务共享系统资源)
Linux系统上所有运行的东西都可以称之为一个进程。
一个比较正式的定义:在自身的虚拟地址空间运行的一个单独的程序
进程 不等于 程序
进程是由程序产生的
程序是静态的命令集合,不占用系统的运行资源
进程是一个随时可能发生变化的、动态的、使用系统运行资源的程序
一个程序可以启动多个进程
进程和程序间的关系可以想象成戏剧和剧本的关系
一个程序可以对应多个进程——>一个剧本可以拿来拍摄多部电视剧
一个进程只能对应一个程序——>一部电视剧只能使用一个剧本
进程的四个要素:
- 要有一段程序供该程序运行
- 进程专用的系统堆栈空间
- 进程控制块(稍后会提到),在Linux中的具体实现是task_struct结构
- 有独立的存储空间
线程
当一个进程缺少四要素的其中一个条件时,我们称其为线程
-
Linux中所有进程都相互联系,除了初始化进程外,所有进程都有一个父进程
-
Linux中所有进程都是由一个进程号为1的init进程衍生而来
-
我们在shell下执行程序启动的进程就是shell的子进程
-
每一个进程都可以再启动自己的子进程,这样就形成了一棵进程树,每个进程都是树中的一个节点,树的根是init
-
Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(Process Control Block)。PCB是系统为了管理进程设置的一个专门的数据结构,用它来记录进程的外部特征,描述进程的运动变化过程。
进程与PCB是一一对应的关系
函数getpid获取进程ID
函数定义:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void)
函数描述:
无参数
返回值为进程的ID
代码描述:
#include <sys/types.h>(定义了linux系统中数据类型的头文件)
#include <unistd.h>
main()
{
printf("The current process ID is %d\n",getpid());
}
函数定义中,getpid的类型为pid_t,从代码描述的输出函数中,getpid的类型为%d,即int类型,由此可知,pid_t和int是兼容的,因为#include <sys/types.h>定义了linux中数据类型的头文件,故调用get_pid的时候,可以省略#include <sys/types.h>这个头文件
进程控制的相关函数
fork和vfork
1 fork
(1)函数原型:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
(2)返回:若成功,父进程中返回子进程ID,子进程中返回0,若出错则返回-1
(3)函数解析
- fork:复制一个进程(当一个进程调用它,完成后就出现两个几乎一模一样的进程)
- 子进程:由fork创建的新进程被称为子进程(child process),将原来的进程称为父进程(parent process)
- 子进程从父进程得到数据段和堆栈段的拷贝,这些需要分配新的内存;对于只读的代码段,通常使用共享内存的方式访问
- fork函数被调用一次,但返回两次,两次返回的区别是子进程的返回值是0,而父进程的返回值是新子进程的进程ID
- fork返回后,父子进程都从调用fork函数的下一条语句开始执行
- 一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的调度算法。
- 现在很多的linux系统中,并不是做一个父进程数据段和堆栈的完全拷贝,因为在fork之后经常跟随着exec
- linux中,创建新进程的方法只有一个,即fork。
(4)fork函数的使用:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int count = 0;
pid_t pid;/*此时仅有一个进程*/
pid = fork();/*此时已经有两个进程同时运行*/
if(pid < 0)
{
printf("error in fork!");
exit(1);
}
else if(pid == 0)
printf("I am the child process,the count is %d,my process ID is %d\n",count,getpid());
else
printf("I am the parent process,the count is %d,my process ID is %d\n",++count,getpid());
return 0;
}
运行结果:I am the parent process,the count is 1,my process ID is 12442
hyx@hyx-virtual-machine:~/test$ I am the child process,the count is 0,my process ID is 12443
从结果可以看出:两个进程有不同的process ID和count值,由此得知,他们占用不同的内存资源。
2 vfork
(1)函数原型:
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
(2)返回:与fork相同,若成功,父进程返回子进程ID,子进程返回0,出错则返回-1
(3)fork与vfork的区别
- fork要拷贝父进程的数据段;vfork不需要完全拷贝父进程的数据段,在子进程没有调用exec或exit之前,子进程与父进程共享数据段
- fork不对父子进程的执行次序进行限制;vfork调用中,子进程先运行,父进程挂起,直到子进程调用了exec或exit之后,父子进程的执行次序才不再有限制。
- 事实上,vfork创建出来的并不是真正意义上的进程,二是一个线程,因为它缺少了进程的四要素的第4项——独立的内存资源
(4)
以下程序说明vfork创建的子进程与父进程之间是共享数据段的,vfork_test1.c代码如下:
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int count = 1;
int child;
printf("before creat son,the father's count is:%d\n",count);
child = vfork();/*此时已经有两个进程在同时运行*/
if(child < 0)
{
printf("error in vfork!");
exit(1);
}/*fork出错退出*/
if(child==0) /*子进程*/
{
printf("this is son,his pid is:%d and the count is:%d\n",getpid(),count++);
exit(1);
}
else /*父进程*/
{
printf("after son,this is father,his pid is:%d and the count is:%d,and the child is:%d\n",getpid(),count,child);
}
return 0;
}
运行结果:
hyx@hyx-virtual-machine:~/test$ ./vfork_test
before creat son,the father's count is:1
this is son,his pid is:12834 and the count is:2
after son,this is father,his pid is:12833 and the count is:2,and the child is:12834
一点理解
我们只对子进程的count做了++,并没有对父进程的count做++,但子进程和父进程的count值都是2,由此可知,子进程和父进程共享数据段(或内存单元),count变量在父子进程中存储在同一个内存单元
(5)
以下代码说明vfork创建的子进程导致父进程挂起,vfork_test2.c代码如下:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int count = 1;
int child;
printf("before create son,the father's count is:%d\n",count);
if(!(child = vfork()))
{
int i;
for(i = 0;i < 100;i++)
{
printf("this is son,the i is:%d\n",i);
if(i == 70)
exit(1);
}
printf("this is son,his pid is:%d and the count is:%d\n",getpid(),++count);
exit(1);
}
else
{
printf("after son,this is father,his pid is:%d and the count is:%d,and the child is:%d\n",getpid(),count,child);
}
return 0;
}
运行结果:
hyx@hyx-virtual-machine:~/test$ ./vfork_test2
before create son,the father's count is:1
this is son,the i is:0
this is son,the i is:1
this is son,the i is:2
this is son,the i is:3
this is son,the i is:4
this is son,the i is:5
this is son,the i is:6
this is son,the i is:7
this is son,the i is:8
this is son,the i is:9
this is son,the i is:10
this is son,the i is:11
this is son,the i is:12
this is son,the i is:13
this is son,the i is:14
this is son,the i is:15
this is son,the i is:16
this is son,the i is:17
this is son,the i is:18
this is son,the i is:19
this is son,the i is:20
this is son,the i is:21
this is son,the i is:22
this is son,the i is:23
this is son,the i is:24
this is son,the i is:25
this is son,the i is:26
this is son,the i is:27
this is son,the i is:28
this is son,the i is:29
this is son,the i is:30
this is son,the i is:31
this is son,the i is:32
this is son,the i is:33
this is son,the i is:34
this is son,the i is:35
this is son,the i is:36
this is son,the i is:37
this is son,the i is:38
this is son,the i is:39
this is son,the i is:40
this is son,the i is:41
this is son,the i is:42
this is son,the i is:43
this is son,the i is:44
this is son,the i is:45
this is son,the i is:46
this is son,the i is:47
this is son,the i is:48
this is son,the i is:49
this is son,the i is:50
this is son,the i is:51
this is son,the i is:52
this is son,the i is:53
this is son,the i is:54
this is son,the i is:55
this is son,the i is:56
this is son,the i is:57
this is son,the i is:58
this is son,the i is:59
this is son,the i is:60
this is son,the i is:61
this is son,the i is:62
this is son,the i is:63
this is son,the i is:64
this is son,the i is:65
this is son,the i is:66
this is son,the i is:67
this is son,the i is:68
this is son,the i is:69
this is son,the i is:70
after son,this is father,his pid is:20575 and the count is:1,and the child is:20576
hyx@hyx-virtual-machine:~/test$