面试题答案
一键面试1. 在现有PCB结构基础上进行扩展
在进程控制块(PCB)中添加以下信息来支持新状态:
- 新状态标志:
在PCB中添加一个状态字段,用于标识进程当前的状态。除了已有的状态(如运行、就绪、阻塞等),增加一个新的值来表示“挂起 - 可中断”状态。例如,假设用一个整型变量
state
表示进程状态,可定义一个新的常量值,如SUSPENDED_INTERRUPTIBLE = 4
。
// 假设PCB结构如下
struct PCB {
int pid;
int state; // 状态字段
// 其他原有字段...
};
- 挂起原因: 添加一个字段记录进程被挂起的原因,这有助于在唤醒进程时进行相应的处理。可以是一个字符串或者一个枚举类型。例如:
struct PCB {
int pid;
int state;
char suspend_reason[50]; // 记录挂起原因
// 其他原有字段...
};
- 信号处理相关: 为了实现特定信号唤醒,需要在PCB中添加与信号处理相关的信息。比如,一个信号掩码(signal mask),用于记录哪些信号可以唤醒该进程。
#include <signal.h>
struct PCB {
int pid;
int state;
char suspend_reason[50];
sigset_t wakeup_signals; // 信号掩码,记录可唤醒信号
// 其他原有字段...
};
2. 状态转换控制机制
从其他状态转换到“挂起 - 可中断”状态
- 从运行状态转换: 当系统检测到资源紧张时,内核调度程序决定将当前运行的进程挂起。首先,将进程的CPU上下文保存到PCB中,以便将来恢复。然后,更新PCB的状态字段为“挂起 - 可中断”,并记录挂起原因。例如:
// 假设当前运行进程的PCB指针为current_pcb
current_pcb->state = SUSPENDED_INTERRUPTIBLE;
strcpy(current_pcb->suspend_reason, "Resource shortage");
// 保存CPU上下文到current_pcb中相关字段
- 从就绪状态转换: 调度程序在选择下一个运行进程时,如果发现系统资源紧张,可能会选择将某个就绪进程挂起。同样,更新该进程PCB的状态字段和挂起原因。
// 假设要挂起的就绪进程的PCB指针为ready_pcb
ready_pcb->state = SUSPENDED_INTERRUPTIBLE;
strcpy(ready_pcb->suspend_reason, "Resource shortage");
- 从阻塞状态转换: 当一个阻塞进程等待的事件短期内无法发生,且系统资源紧张时,内核可以将其转换为“挂起 - 可中断”状态。更新PCB状态和挂起原因,并处理相关的资源释放等操作。
// 假设要挂起的阻塞进程的PCB指针为blocked_pcb
blocked_pcb->state = SUSPENDED_INTERRUPTIBLE;
strcpy(blocked_pcb->suspend_reason, "Resource shortage and long - wait event");
从“挂起 - 可中断”状态转换到其他状态
- 转换到就绪状态:
当进程接收到其
wakeup_signals
中记录的特定信号时,内核将该进程从“挂起 - 可中断”状态唤醒。首先,检查信号是否有效,然后恢复进程的CPU上下文(如果之前保存过),并将其状态更新为就绪状态,以便调度程序可以将其调度到运行状态。
// 假设接收到信号的挂起进程的PCB指针为suspended_pcb
if (sigismember(&suspended_pcb->wakeup_signals, received_signal)) {
suspended_pcb->state = READY;
// 恢复CPU上下文(如果之前保存过)
}
- 其他转换(如直接转换到运行状态,在一些特殊调度策略下可能发生): 在某些情况下,如系统资源突然变得充足且该挂起进程优先级较高,调度程序可能决定直接将其从“挂起 - 可中断”状态转换到运行状态。同样,需要恢复CPU上下文,并更新状态字段。
// 假设要直接运行的挂起进程的PCB指针为suspended_pcb
if (special_condition) {
suspended_pcb->state = RUNNING;
// 恢复CPU上下文
}