一、进程状态转换基础
进程是操作系统调度的基本单位,而进程状态则是描述进程执行过程中状态的基本概念。进程在其生命周期中会处于不同的状态,包括新建态、就绪态、运行态、阻塞态和终止态。
新建态是指进程被创建后还未被分配资源的状态,就绪态是指进程已经获取到了所有必要资源等待执行的状态,运行态是指进程正在占用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系统中还有很多其它的状态转换方式,大家可以自行深入学习。