1.进程的定义
进程的概念首先是在60年代初期由MIT的Multics系统和IBM的TSS/360系统引入的。
经过了40 多年的发展,人们对进程有过各种各样的定义。现列举较为著名的几种。
(1)进程是一个独立的可调度的活动(E. Cohen,D. Jofferson)
(2)进程是一个抽象实体,当它执行某个任务时,将要分配和释放各种资源(P. Denning)
(3)进程是可以并行执行的计算部分。(S. E. Madnick,J. T. Donovan)
以上进程的概念都不相同,但其本质是一样的。它指出了进程是一个程序的一次执行的
过程。它和程序是有本质区别的,程序是静态的,它是一些保存在磁盘上的指令的有序集合,
没有任何执行的概念;而进程是一个动态的概念,它是程序执行的过程,包括了动态创建、
调度和消亡的整个过程。它是程序执行和资源管理的最小单位。因此,对系统而言,当用户
在系统中键入命令执行一个程序的时候,它将启动一个进程。
2.进程控制块
进程是 Linux 系统的基本调度单位,那么从系统的角度看如何描述并表示它的变化呢?
在这里,是通过进程控制块来描述的。进程控制块包含了进程的描述信息、控制信息以及资
源信息,它是进程的一个静态描述。在Linux 中,进程控制块中的每一项都是一个task_struct
结构,它是在include/linux/sched.h中定义的。
3.进程的标识
在 Linux 中最主要的进程标识有进程号(PID,Process Idenity Number)和它的父进程号
(PPID,parent process ID)。其中PID 惟一地标识一个进程。PID 和PPID 都是非零的正整数。
在 Linux 中获得当前进程的PID 和PPID 的系统调用函数为getpid和getppid,通常程序
获得当前进程的PID 和PPID 可以将其写入日志文件以做备份。getpid和getppid系统调用过
程如下所示:
/*process.c*/
#include
#include
#include
int main()
{
/*获得当前进程的进程ID和其父进程ID*/
printf("The PID of this process is %d\n",getpid());
printf("The PPID of this process is %d\n",getppid());
}
# ./process
The PID of this process is 78
THe PPID of this process is 36
4.进程运行的状态
进程是程序的执行过程,根据它的生命期可以划分成3 种状态。
· 执行态:该进程正在,即进程正在占用CPU。
· 就绪态:进程已经具备执行的一切条件,正在等待分配CPU的处理时间片。
· 等待态:进程不能使用CPU,若等待事件发生则可将其唤醒。
进程创建
1.fork()
在 Linux 中创建一个新进程的惟一方法是使用fork函数。fork 函数是Linux 中一个非常
重要的函数,和读者以往遇到的函数也有很大的区别,它执行一次却返回两个值。希望读者
能认真地学习这一部分的内容。
(1)fork函数说明
fork 函数用于从已存在进程中创建一个新进程。新进程称为子进程,而原进程称为父进
程。这两个分别带回它们各自的返回值,其中父进程的返回值是子进程的进程号,而子进程
则返回0。因此,可以通过返回值来判定该进程是父进程还是子进程。
使用fork函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地
址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程
优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等,而子进程所独有的只
有它的进程号、资源使用和计时器等。因此可以看出,使用fork函数的代价是很大的,它复
制了父进程中的代码段、数据段和堆栈段里的大部分内容,使得fork 函数的执行速度并不
很快。
(2)fork函数语法
所需头文件#include // 提供类型pid_t 的定义
#include
函数原型 pid_t fork(void)
函数返回值 0:子进程
子进程ID(大于0的整数):父进程
-1:出错
(3)fork函数使用实例
/*fork.c*/
#include
#include
#include
#include
int main(void)
{
pid_t result;
/*调用fork函数,其返回值为result*/
result = fork();
/*通过result的值来判断fork函数的返回情况,首先进行出错处理*/
if(result == -1){
perror("fork");
exit;
}
/*返回值为0代表子进程*/
else if(result == 0){
printf("The return value is %d\nIn child process!!\nMy PID is%d\n",result,getpid());
}
/*返回值大于0代表父进程*/
else
{
printf("The return value is %d\nIn father process!!\nMy PID is
%d\n",result,getpid());
}
}
运行结果如下所示:
The return valud s 76
In father process!!
My PID is 75
The return value is :0
In child process!!
My PID is 76
从该实例中可以看出,使用fork 函数新建了一个子进程,其中的父进程返回子进程的
PID,而子进程的返回值为0。
(4)函数使用注意点
fork函数使用一次就创建一个进程,所以若把fork函数放在了if else判断语句中则要小
心,不能多次使用fork函数。
小知识:
由于 fork 完整地拷贝了父进程的整个地址空间,因此执行速度是比较慢的。为了加快fork 的
执行速度,有些UNIX系统设计者创建了vfork。vfork也能创建新进程,但它不产生父进程的
副本。它是通过允许父子进程可访问相同物理内存从而伪装了对进程地址空间的真实拷贝,
当子进程需要改变内存中数据时才拷贝父进程。这就是著名的“写操作时拷贝”(copy-on-write)
技术。
现在很多嵌入式Linux 系统的fork 函数调用都采用vfork 函数的实现方式,实际上uClinux所
有的多进程管理都通过vfork来实现。
阅读(644) | 评论(0) | 转发(0) |