1、进程与程序的概念:
进程:进程是在操作系统中运行的特定程序,或执行的任务。强调的是程序的运行过程,是动态的。
程序:程序是存储在磁盘上包含可执行机器指令和数据的静态实体。是静态的。
2、二者的相同点:
进程是一个随执行过程不断变化的实体。和程序要包含指令和数据一样,进程也包含程序计数器和所有CPU寄存器的值,同时它的堆栈中存储着如子程序参数、返回地址以及变量之类的临时数据。
3、Linux进程
为了让Linux来管理系统中的进程,每个进程用一个task_struct数据结构来表示(任务与进程在Linux中可以混用)。数组task包含指向系统中所有task_struct结构的指针。
这意味着系统中的最大进程数目受task数组大小的限制,缺省值一般为512。创建新进程时,Linux将从系统内存中分配一个task_struct结构并将其加入task数组。 当前运行进程的结构用current指针来指示。
管理进程的结构体task_struct的定义在:linux-2.6.30.4/
include/linux/sched.h
中,如下所示:
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
int lock_depth; /* BKL lock depth */
...........
int exit_state; .........
.........
};
3.1 进程的状态 state
1、进程状态定义
volatile long state;
int exit_state;
2、state成员的可能取值如下:
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define __TASK_STOPPED 4
#define __TASK_TRACED 8
/* in tsk->exit_state */
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
/* in tsk->state again */
#define TASK_DEAD 64
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
3、相关状态的解释。
系统中的每个进程都必然处于以上所列进程状态中的一种。
TASK_RUNNING :运行态或就绪态。表示进程要么正在执行,要么正要准备执行。
TASK_INTERRUPTIBLE :浅睡眠状态。表示进程被阻塞。能响应信号,直到被唤醒,进程的状态就被设置为 TASK_RUNNING。
TASK_UNINTERRUPTIBLE :深睡眠状态。的意义与TASK_INTERRUPTIBLE类似,无法响应信号。
该进程等待一个事件的发生或某种系统资源。
__TASK_STOPPED :停止态 。表示进程被停止执行。
__TASK_TRACED :
对于进程本身来说,TASK_STOPPED和TASK_TRACED状态很类似,都是表示进程暂停下来。
而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护, 处于TASK_TRACED状态
而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护, 处于TASK_TRACED状态
的进程不能响应SIGCONT信号而被唤醒。
只能等到调试进程通过ptrace系统调用执行PTRACE_CONT、
PTRACE_DETACH等操作
(通过ptrace系统调用的参数指定操作),
或调试进程退出,
被调试的进程才能恢复TASK_RUNNING状态。
EXIT_ZOMBIE :僵尸态。此时进程不能被调度,但是PCB 未被释放。
EXIT_DEAD :死亡态。表示一个已终止的进程,其PCB被释放。
EXIT_ZOMBIE和EXIT_DEAD 也可以存放在 exit_state 成员中。进程状态的切换过程和原因大致如下图(图片来自《Linux Kernel Development》):
4、关于进程的挂起与阻塞
本人的理解是:进程的阻塞对应的是:
TASK_INTERRUPTIBLE 或者 TASK_UNINTERRUPTIBLE
这两种状态,一般是被动产生的,
而挂起状态则一般是通过相应函数去主动使进程挂起的。
以下是网上相关说法理解,本人认为分析得比较清晰的一个版本:
- 理解一:挂起是一种主动行为,因此恢复也应该要主动完成,而阻塞则是一种被动行为,是在等待事件或资源时任务的表现,你不知道他什么时候被阻塞(pend),也就不能确切的知道他什么时候恢复阻塞。而且挂起队列在操作系统里可以看成一个,而阻塞队列则是不同的事件或资源(如信号量)就有自己的队列。
- 理解二:阻塞(pend)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。挂起(suspend)不释放CPU,如果任务优先级高就永远轮不到其他任务运行,一般挂起用于程序调试中的条件中断,当出现某个条件的情况下挂起,然后进行单步调试。
- 理解三:pend是task主动去等一个事件,或消息.suspend是直接悬挂task,以后这个task和你没任何关系,任何task间的通信或者同步都和这个suspended task没任何关系了,除非你resume task;
- 理解四:任务调度是操作系统来实现的,任务调度时,直接忽略挂起状态的任务,但是会顾及处于pend下的任务,当pend下的任务等待的资源就绪后,就可以转为ready了。ready只需要等待CPU时间,当然,任务调度也占用开销,但是不大,可以忽略。可以这样理解,只要是挂起状态,操作系统就不在管理这个任务了。
- 理解五:挂起是主动的,一般需要用挂起函数进行操作,若没有resume的动作,则此任务一直不会ready。而阻塞是因为资源被其他任务抢占而处于休眠态。两者的表现方式都是从就绪态里“清掉”,即对应标志位清零,只不过实现方式不一样。