您的位置:

进程状态转换图

一、进程状态转换基础

进程是操作系统调度的基本单位,而进程状态则是描述进程执行过程中状态的基本概念。进程在其生命周期中会处于不同的状态,包括新建态、就绪态、运行态、阻塞态和终止态。

新建态是指进程被创建后还未被分配资源的状态,就绪态是指进程已经获取到了所有必要资源等待执行的状态,运行态是指进程正在占用CPU运行的状态,阻塞态是指进程等待某些条件满足或资源释放的状态,终止态是指进程执行结束且已经被释放的状态。

当进程在不同状态之间切换的时候,需要进行状态转换操作。下面我们以Linux作为例子来介绍进程在状态之间的转换操作。

/* 进程状态 */
enum task_state {
    TASK_RUNNING = 0,   /* 运行态 */
    TASK_INTERRUPTIBLE, /* 可中断的睡眠态 */
    TASK_UNINTERRUPTIBLE,   /* 不可中断的睡眠态 */
    TASK_STOPPED,   /* 停止态 */
    TASK_TRACED,    /* 被追踪态 */
    TASK_DEAD,  /* 已终止态 */
};

二、进程状态转换图

进程的状态转换有多种可能,这里我们以一种典型的转换方式为例来说明。下面是进程状态转换图:

+--------+        +----------+       +---------+       +---------+
| 创建态 +------->+ 就绪态   +------>+ 运行态  +------>| 终止态  |
+--------+        +----------+       +---------+       +---------+
                   ^   |  ^                |
                   |   |  |                |
                   |   V  |                |
             +--------------+         +-----------+
             | 可中断的睡眠态 |<--------+ 不可中断的睡眠态 |
             +--------------+         +-----------+

三、进程状态之间的转换

下面我们来分别介绍进程状态之间的转换方式。

1. 创建态到就绪态

当一个进程被创建时,初始状态为创建态。当进程被分配到所有必要资源,可以开始执行之前,由创建态转为就绪态。这个转换是由系统调度算法决定的,通常是通过进程队列和调度程序来实现的。

/* 创建一个新进程并将其加入到就绪队列 */
struct task_struct *init_task(void)
{
    /* ...省略其他代码... */
    /* 创建进程 */
    p = __alloc_task_struct();
    /* 设置进程状态为就绪态 */
    p->state = TASK_RUNNING;
    /* 将进程加入到就绪队列 */
    enqueue_task(p, &rq->array[rq->curr]);
    return p;
}

2. 就绪态到运行态

当CPU被分配到了进程时,该进程进入运行态。如果此时还有其他进程处于就绪态,则它们将继续等待CPU资源的分配。

/* 进程从就绪态变为运行态 */
static void __sched __schedule(void)
{
    /* ...省略其他代码... */
    /* 获取就绪队列里的下一个进程,并将其状态设置为运行态 */
    next = pick_next_task(rq);
    next->state = TASK_RUNNING;

    /* 切换到下一个进程 */
    rq->curr = next;
    context_switch(rq, prev, next);
}

3. 运行态到就绪态

当一个进程正在占用CPU运行时,如果出现IO等等其它需要等待的操作,则该进程从运行态进入阻塞态,然后进入可中断的睡眠态或者不可中断的睡眠态,等待IO等操作结束后再转为就绪态。此时,其他进程有可能获得CPU使用权。

/* 进程从运行态变为阻塞态 */
void sleep_on(wait_queue_head_t *q)
{
    /* ...省略其他代码... */
    //将当前进程的状态设置为可中断的睡眠态
    current->state = TASK_INTERRUPTIBLE;
    //将当前进程加入到等待队列中
    add_wait_queue(q, &wait);
    //切换到下一个进程
    schedule();
}

4. 阻塞态到就绪态

当阻塞态的进程等待的系统调用返回并且获得了系统资源时,它从睡眠态或者阻塞态变成就绪态,表示该进程的资源需求已得到满足,可以开始运行了。

/* 进程从阻塞态变为就绪态 */
void wake_up(wait_queue_head_t *q)
{
    /* ...省略其他代码... */
    //将等待队列中阻塞进程的状态设置为就绪态
    do_each_thread(g, p) {
        if (p->state == state &&
            (wait == NULL || wait->func(wait, task, mode, key) != 0))
            p->state = TASK_RUNNING;
    } while_each_thread(g, p);
    /* 移除等待队列中的进程 */
    __remove_wait_queue(q, &wait);
    /* 切换到下一个进程 */
    schedule();
}

5. 运行态到终止态

进程在完成任务后或者出错时,会从运行态进入终止态。在终止态中,进程进行善后处理和资源释放。此后,内核将不再管理此进程,以便其它进程使用其资源。

/* 进程从运行态变为终止态 */
asmlinkage void do_exit(long code)
{
    /* ...省略其他代码... */
    //设置进程状态为终止态
    current->state = TASK_DEAD;
    //从进程表中删除该进程
    del_from_tasklist(current);
    /* 切换到下一个进程 */
    schedule();
}

结语

进程的状态转换是操作系统中非常关键的一个概念。我们通过介绍进程的五种状态和相应的转换方式,使读者加深对进程状态转换的理解。其实,在Linux系统中还有很多其它的状态转换方式,大家可以自行深入学习。