中断睡眠(Interruptible Sleep)和不可中断睡眠(Uninterruptible Sleep)

在操作系统中,进程的睡眠状态是为了让进程在等待某些条件时释放CPU资源,避免空转。睡眠分为可中断和不可中断两种,它们的核心区别在于是否可以被信号(Signal)或其他事件打断。


1. 可中断睡眠(Interruptible Sleep)

  • 定义
    进程在等待某些条件时进入可中断睡眠状态,此时进程可以被信号或事件唤醒。

  • 睡眠的原因
    进程进入可中断睡眠通常是因为需要等待以下条件:

    • 用户输入(如键盘、鼠标输入)。

    • 网络数据到达(如等待Socket数据)。

    • 某些资源可用(如等待锁释放)。

    • 定时器到期(如sleep()函数)。

  • 中断的含义
    这里的“中断”指的是进程可以被信号(Signal)或其他事件唤醒。例如:

    • 如果进程正在等待用户输入,但用户发送了一个终止信号(如SIGKILLSIGTERM),进程会立即退出睡眠状态并处理信号。

    • 如果进程正在等待网络数据,但数据迟迟未到,管理员可以发送信号强制终止进程。

  • 特点

    • 进程可以被信号唤醒。

    • 进程在睡眠期间会释放CPU资源。

    • 适用于可以被打断的任务。

  • 示例

    // 可中断睡眠的示例:等待用户输入
    read(fd, buffer, size);  // 如果数据未到达,进程进入可中断睡眠

2. 不可中断睡眠(Uninterruptible Sleep)

  • 定义
    进程在等待某些关键条件时进入不可中断睡眠状态,此时进程无法被信号或事件唤醒,必须等待条件满足。

  • 睡眠的原因
    进程进入不可中断睡眠通常是因为需要等待以下条件:

    • 硬件I/O操作完成(如磁盘读写)。

    • 内核级别的任务完成(如内存页交换)。

    • 某些必须完成的操作(如文件系统操作)。

  • 中断的含义
    这里的“中断”指的是进程无法被信号或事件唤醒。即使管理员发送了终止信号(如SIGKILL),进程也不会退出睡眠状态,直到等待的条件完成。

  • 特点

    • 进程无法被信号唤醒。

    • 进程会一直阻塞,直到条件满足。

    • 适用于必须完成的任务。

  • 示例

    // 不可中断睡眠的示例:等待磁盘I/O完成
    write(fd, buffer, size);  // 如果磁盘I/O未完成,进程进入不可中断睡眠

3. 中断的具体含义

  • 中断(Interrupt)
    在操作系统中,中断是指外部事件或信号打断当前进程的执行。中断可以是硬件中断(如键盘输入、磁盘I/O完成)或软件中断(如信号)。

  • 可中断睡眠的中断
    进程可以被信号或事件唤醒,例如:

    • 用户按下Ctrl+C发送SIGINT信号。

    • 管理员发送SIGTERM信号终止进程。

  • 不可中断睡眠的中断
    进程无法被信号或事件唤醒,例如:

    • 即使发送SIGKILL信号,进程也不会退出睡眠状态,直到等待的条件完成。


4. 实际场景中的区别

  • 可中断睡眠

    • 适用于可以被打断的任务,如等待用户输入、网络数据等。

    • 进程可以响应信号,适合需要灵活控制的场景。

  • 不可中断睡眠

    • 适用于必须完成的任务,如磁盘I/O、文件系统操作等。

    • 进程无法响应信号,适合需要确保任务完成的场景。


5. 总结

特性可中断睡眠(Interruptible Sleep)不可中断睡眠(Uninterruptible Sleep)
是否可被信号唤醒
睡眠原因等待用户输入、网络数据、锁释放等等待磁盘I/O、硬件操作、内核任务等
适用场景可被打断的任务必须完成的任务
示例read()sleep()write()、磁盘I/O操作

6. 以下是它们的底层实现细节:

6.1. 进程状态

在Linux内核中,进程的状态由task_struct结构体中的state字段表示。常见的进程状态包括:

  • TASK_INTERRUPTIBLE:可中断睡眠状态。

  • TASK_UNINTERRUPTIBLE:不可中断睡眠状态。

  • TASK_RUNNING:运行状态。

  • TASK_STOPPED:停止状态。


6.2. 可中断睡眠的底层实现
  • 状态设置
    当进程进入可中断睡眠时,内核会将进程的state字段设置为TASK_INTERRUPTIBLE

  • 加入等待队列
    进程会被加入到一个等待队列(wait queue)中,等待特定条件(如I/O完成、信号到达等)。等待队列是一个内核数据结构,用于管理等待同一条件的多个进程。

  • 调度器行为
    进程进入睡眠后,调度器会将其从运行队列中移除,并选择其他进程运行。此时,进程不会占用CPU资源。

  • 唤醒机制
    当条件满足(如I/O完成)或信号到达时,内核会调用wake_up()wake_up_interruptible()函数,将进程从等待队列中移除,并将其状态设置为TASK_RUNNING,重新加入运行队列。

  • 信号处理
    如果进程在睡眠期间收到信号,内核会检查信号是否可以被处理。如果可以,进程会被提前唤醒,并处理信号。

  • 代码示例

    // 进入可中断睡眠
    wait_event_interruptible(wait_queue, condition);
    // 唤醒可中断睡眠的进程
    wake_up_interruptible(&wait_queue);

6.3. 不可中断睡眠的底层实现
  • 状态设置
    当进程进入不可中断睡眠时,内核会将进程的state字段设置为TASK_UNINTERRUPTIBLE

  • 加入等待队列
    进程同样会被加入到一个等待队列中,等待特定条件(如硬件I/O完成)。

  • 调度器行为
    进程进入睡眠后,调度器会将其从运行队列中移除,并选择其他进程运行。此时,进程不会占用CPU资源。

  • 唤醒机制
    当条件满足(如硬件I/O完成)时,内核会调用wake_up()函数,将进程从等待队列中移除,并将其状态设置为TASK_RUNNING,重新加入运行队列。

  • 信号处理
    不可中断睡眠的进程不会响应信号。即使收到SIGKILL信号,进程也不会被唤醒,直到条件满足。

  • 代码示例

    // 进入不可中断睡眠
    wait_event(wait_queue, condition);
    // 唤醒不可中断睡眠的进程
    wake_up(&wait_queue);

6.4. 等待队列的实现

等待队列是内核中用于管理睡眠进程的核心数据结构。它的主要作用是:

  • 将等待同一条件的进程组织在一起。

  • 在条件满足时唤醒队列中的进程。

等待队列的核心数据结构是wait_queue_head_t,其定义如下:

struct wait_queue_head {
    spinlock_t lock;           // 自旋锁,用于保护队列
    struct list_head head;     // 链表头,用于连接等待的进程
};
  • 加入等待队列
    进程通过add_wait_queue()函数将自己加入等待队列。

  • 移除等待队列
    进程通过remove_wait_queue()函数将自己从等待队列中移除。


6.5. 调度器的角色
  • 当进程进入睡眠状态时,调度器会将其从运行队列中移除。

  • 当进程被唤醒时,调度器会将其重新加入运行队列,并根据优先级决定是否立即调度该进程。


6.6. 信号处理的区别
  • 可中断睡眠
    进程在睡眠期间会检查信号。如果收到信号,内核会调用signal_pending()函数检查是否有未处理的信号。如果有,进程会被唤醒并处理信号。

  • 不可中断睡眠
    进程在睡眠期间不会检查信号。即使收到信号,进程也不会被唤醒,直到条件满足。


6.7. 总结
特性可中断睡眠(TASK_INTERRUPTIBLE)不可中断睡眠(TASK_UNINTERRUPTIBLE)
状态设置state = TASK_INTERRUPTIBLEstate = TASK_UNINTERRUPTIBLE
等待队列加入等待队列,可被信号唤醒加入等待队列,不可被信号唤醒
调度器行为从运行队列中移除从运行队列中移除
唤醒机制wake_up_interruptible()wake_up()
信号处理可被信号唤醒不可被信号唤醒

通过以上机制,操作系统能够高效地管理进程的睡眠和唤醒,确保资源的合理分配和任务的顺利完成。

 

3-2 进程状态 3-2-1 Linux内核源代码怎么说 • 为了弄明⽩正在运⾏的进程是什么意思,我们需要知道进程的不同状态。⼀个进程可以有⼏个状 态(在Linux内核⾥,进程有时候也叫做任务)。 下⾯的状态在kernel源代码⾥定义: /* *The task state array is a strange "bitmap" of *reasons to sleep. Thus "running" is zero, and *you can test for combinations of others with *simple bit tests. */ static const char *const task_state_array[] = { "R (running)", /*0 */ "S (sleeping)", /*1 */ "D (disk sleep)", /*2 */ "T (stopped)", /*4 */ "t (tracing stop)", /*8 */ "X (dead)", /*16 */ "Z (zombie)", /*32 */ }; • R运⾏状态(running): 并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏ 队列⾥。 • S睡眠状态(sleeping): 意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠interruptible sleep))。 • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个 状态的进程通常会等待IO的结束。 • T停⽌状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停⽌(T)进程。这个被暂停的 进程可以通过发送 SIGCONT 信号让进程继续运⾏。 • X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。请举例丰富的例子来说明下上面关于linux进程的所有详细说明
最新发布
07-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值