1.1进程状态:
运行态、就绪态、封锁态(等待态、阻塞态、挂起态)。
其中,处于运行态的进程只能等于CPU的数量,比如单核CPU 的机器只能同时一个进程在运行
处于就绪和封锁态的进程可以有很多,具体看下:
实际系统更为复杂,多了两个状态:新建态、终止态,具体如下:
以上是在内存状态的调度情况,但是当进程更加多更加复杂的时候,内存资源不足的时候,可是依然有进程创建,此时怎么办?随着需求,就有了主存和辅存:
活跃就绪:是指进程在主存并且可被调度的状态。
静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。
活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。
静止阻塞:是指进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。
1.2 进程模式
用户模式:
用户程序、应用程序、内核以外的程序。
内核模式:
当出现系统调用、中断事件、异常等的时候,进程模式会切换到内核模式。【也就是:用户进程可以在两种模式下运行】
可以执行机器的特权指令,并且此时不受用户甚至root用户干预,内核态高于所有用户态的运行
1.3:线程
有时也称为轻型的进程。
linux线程具有:一段可执行的程序、专用的系统堆栈空间、私有的进程控制块(task_struct 数据结构),本来应该有独立的存储空间,但是大量的线程要是都占用无力内存作为自己的独立存储空间,显然不够,代替的是独立的虚拟内存空间。【参考详情看这里:linux进程空间 Linux 用户进程内存空间详解】
1.4:进程属性:
程序是静态的,是一些保存在磁盘上的可执行代码和数据的集合,而进程是动态的,是一个程序动态执行的一个过程,是系统调度的单位。
更多参考:http://book.51cto.com/art/200902/111548.htm
2:进程结构
既然进程是一个动态的过程,那么它自然也就是加载到内存里边的东西,这样可以被操作系统调度,进而处理程序的内部逻辑。加载到内存,所以它的结构涉及到保存的方式、位置。基本结构由3部分组成:代码段、数据段、堆栈段,也就是程序、数据、PCB进程控制块。而进程工作的核心便是PCB 控制的流程,因此PCB是进程存在的唯一标志,操作系统通过PCB的存在而感知进程的存在。
代码段:存放程序的可执行代码,比如对于EXE文件,里边的可执行代码是汇编代码对应的十六进制指令。
数据段:存放程序里边的常量、全局变量、静态变量。
堆栈段:分为堆和栈,其中,堆动态分配内存的变量,栈用于函数调用过程中,函数的参数以及函数内部的局部变量。
在linux中,进程控制块使用的是一个结构体:task_struct,它主要包含成员有:
进程状态
调度信息
标志符 PID
内部进程通信 : 管道、信号、信号量等
链接信息
时间和计时器
文件系统
虚拟内存
处理器信息
详情见这里:进程控制块 进程的概念与结构 理解Linux下进程的结构
当内核在为进程分配task_struct结构的内存空间的时候,实际上是一次性分配8K的物理内存空间,其中1K用来存放task_struct结构,7K用来存放 进程 的系统空间堆栈。
3.1:进程的创建
我们使用到的都是调用系统调用:fork() 和 clone(),新进程是通过复制父进程而创建的。二者区别在于:
fork是将父进程全部资源通过数据结构的复制“传给”子进程,它是无参数的
clone是有选择的将父进程资源复制给子进程,没有复制的数据结构则通过指针的复制让子进程共享,因此它是有参数的
创建过程:
系统从无力内存中为它分配一个task_struct数据结构和进程系统堆栈,新的task_struct数据结构加入到进程向量中,系统为该进程指定一个唯一的PID,之后进行资源的复制,例如:task_struct数据结构、系统空间堆栈、页表等,也就是堆栈段,而对于父进程的代码段和数据段中的全局变量不复制,仅仅通过只读方式实现与父进程的共享。
3.2进程的等待
父进程创建子进程后往往要让子进程替自己做一些辅助工作,因此父进程创建子进程后,有两种处理方式:同步等待、异步处理。
同步等待:
等到子进程运行终止才继续进行。
父进程调用系统调用:
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
wait3是等待任意一个子进程终止,wait4是等待特定的进程终止,但是目前这些函数“太古老”已经被放弃使用,取而代之的是:
int waitpid(-1, status, options);
int waitpid(pid, status, options);
返回结果是子进程的pid
man 查询结果:
例子:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
pid_t childpid;
int status;
childpid = fork();
if ( childpid < 0 )
{
perror( "fork()" );
exit( EXIT_FAILURE );
}
else if ( childpid == 0 )
{
puts( "In child process" );
sleep( 3 );//让子进程睡眠3秒,看看父进程的行为
printf("\tchild pid = %d\n", getpid());
printf("\tchild ppid = %d\n", getppid());
exit(EXIT_SUCCESS);
}
else
{
int pid = waitpid( childpid, &status, 0 );
puts( "in parent" );
printf( "\treturn pid = %d\n",pid);
printf( "\tparent pid = %d\n", getpid() );
printf( "\tparent ppid = %d\n", getppid() );
printf( "\tchild process exited with status %d \n", status );
}
exit(EXIT_SUCCESS);
}
异步处理:
这个是我自己感觉的例子,不知道是否准确:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
更多内容:见这里
3.3进程的终止
3.4进程调度