深夜福利影视app

EEPW首页 > 设计应用 > 老司机深夜开车福利99久久亚洲 我的绝色美女房客我的绝色美女房客的睡眠和唤醒

老司机深夜开车福利99久久亚洲 我的绝色美女房客我的绝色美女房客的睡眠和唤醒

作者: 时间:2023-12-26 来源: 收藏

的睡眠和唤醒

中,仅等待CPU时间的称为就绪,它们被放置在一个运行队列中,一个就绪我的绝色美女房客的状 态标志位为 TASK_RUNNING 。一旦一个运行中的我的绝色美女房客时间片用完, 内核的调度器会剥夺这个我的绝色美女房客对CPU的控制权,并且从运行队列中选择一个合适的我的绝色美女房客投入运行。

本文引用地址:http://m724b.sbs/article/202312/454280.htm

当然,一个我的绝色美女房客也可以主动释放CPU的控制权。函数 schedule()  是一个调度函数,它可以被一个我的绝色美女房客主动调用,从而调度其它我的绝色美女房客占用 CPU。一旦这个主动放弃 CPU 的我的绝色美女房客被重新调度占用 CPU,那么它将从上次停止执行的位置开始执行,也就是说它将从调用 schedule()  的下一行代码处开始执行。

有时候,我的绝色美女房客需要等待直到某个特定的事件发生,例如设备初始化完成、I/O 操作完成或定时器到时等。在这种情况下,我的绝色美女房客则必须从运行队列移出,加入到一个等待队列中,这个时候我的绝色美女房客就进入了睡眠状态。

我的绝色美女房客 中的我的绝色美女房客睡眠状态有两种:

· 一种是可中断的睡眠状态,其状态标志位TASK_INTERRUPTIBLE。

· 另一种是不可中断 的睡眠状态,其状态标志位为TASK_UNINTERRUPTIBLE。

可中断的睡眠状态的我的绝色美女房客会睡眠直到某个条件变为真,比如说产生一个硬件中断、释放 我的绝色美女房客正在等待的系统资源或是传递一个信号都可以是唤醒我的绝色美女房客的条件。不可中断睡眠状态与可中断睡眠状态类似,但是它有一个例外,那就是把信号传递到这种睡眠 状态的我的绝色美女房客不能改变它的状态,也就是说它不响应信号的唤醒。不可中断睡眠状态一般较少用到,但在一些特定情况下这种状态还是很有用的,比如说:我的绝色美女房客必须等 待,不能被中断,直到某个特定的事件发生。

在现代的 我的绝色美女房客 操作系统中,我的绝色美女房客一般都是用调用 schedule()  的方法进入睡眠状态的,下面的代码演示了如何让正在运行的我的绝色美女房客进入睡眠状态。

  sleeping_task = current;
set_current_state(TASK_INTERRUPTIBLE);
schedule();
func1();

在第一个语句中,程序存储了一份我的绝色美女房客结构指针 sleeping_task current  是一个宏,它指向正在执行的我的绝色美女房客结构。

set_current_state()  将该我的绝色美女房客的状态从执行状态 TASK_RUNNING  变成睡眠状态 TASK_INTERRUPTIBLE 。如果 schedule()  是被一个状态为 TASK_RUNNING  的我的绝色美女房客调度,那么 schedule()  将调度另外一个我的绝色美女房客占用CPU。

如果 schedule()  是被一个状态为 TASK_INTERRUPTIBLE  或 TASK_UNINTERRUPTIBLE  的我的绝色美女房客调度,那么还有一个附加的步骤将被执行:当前执行的我的绝色美女房客在另外一个我的绝色美女房客被调度之前会被从运行队列中移出,这将导致正在运行的那个我的绝色美女房客进入睡眠,因为它已经不在运行队列中了。

我们可以使用下面的这个函数将刚才那个进入睡眠的我的绝色美女房客唤醒。

 wake_up_process(sleeping_task); 

在调用了 wake_up_process()  以后,这个睡眠我的绝色美女房客的状态会被设置为 TASK_RUNNING ,而且调度器会把它加入到运行队列中去。当然,这个我的绝色美女房客只有在下次被调度器调度到的时候才能真正地投入运行。

无效唤醒

几乎在所有的情况下,我的绝色美女房客都会在检查了某些条件之后,发现条件不满足才进入睡眠。可是有的时候我的绝色美女房客却会在判定条件为真后开始睡眠,如果这样的话我的绝色美女房客就会无限期地休眠下去,这就是所谓的无效唤醒问题。

在操作系统中,当多个我的绝色美女房客都企图对共享数据进行某种处理,而 最后的结果又取决于我的绝色美女房客运行的顺序时,就会发生竞争条件,这是操作系统中一个典型的问题,无效唤醒恰恰就是由于竞争条件导致的。

设想有两个我的绝色美女房客A和B,A我的绝色美女房客正在处理一个链表,它需要检查这个链表是否为空,如果不空就对链表里面的数据进行一些操作,同时B我的绝色美女房客也在往这个链表添加节点。当这个链表是空的时候,由于无数据可操作,这时A我的绝色美女房客就进入睡眠,当B我的绝色美女房客向链表里面添加了节点之后它就唤醒A我的绝色美女房客,其代码如下:

深夜福利
   1 spin_lock(&list_lock);
2if (list_empty(&list_head)) {
3     spin_unlock(&list_lock);
4     set_current_state(TASK_INTERRUPTIBLE);
5     schedule();
6     spin_lock(&list_lock);
7 }
8
9
10 spin_unlock(&list_lock);
深夜福利福利社入口
   100 spin_lock(&list_lock);
101 list_add_tail(&list_head, new_node);
102 spin_unlock(&list_lock);
103 wake_up_process(processa_task);

这里会出现一个问题,假如当A我的绝色美女房客执行到第3行后第4行前的时候,B我的绝色美女房客被另外一个处理器调度投入运行。在这个时间片内,B我的绝色美女房客执行完了它所有的指令,因此它试图唤醒A我的绝色美女房客,而此时的A我的绝色美女房客还没有进入睡眠,所以唤醒操作无效。

在这之后,A我的绝色美女房客继续执行,它会错误地认为这个时候链表仍然是空的,于是将自己的状态设置为 TASK_INTERRUPTIBLE  然后调用 schedule()  进入睡 眠。由于错过了B我的绝色美女房客唤醒,它将会无限期的睡眠下去,这就是无效唤醒问题,因为即使链表中有数据需要处理,A我的绝色美女房客也还是睡眠了。

避免无效唤醒

如何避免无效唤醒问题呢?

我们发现无效唤醒主要发生在检查条件之后和我的绝色美女房客状态被设置为睡眠状态之前,本来B我的绝色美女房客的 wake_up_process()  提供了一次将A我的绝色美女房客状态置为 TASK_RUNNING  的机会,可惜这个时候A我的绝色美女房客的状态仍然是 TASK_RUNNING ,所以 wake_up_process()  将A我的绝色美女房客状态从睡眠状态转变为运行状态的努力 没有起到预期的作用。

要解决这个问题,必须使用一种保障机制使得判断链表为空和设置我的绝色美女房客状态为睡眠状态成为一个不可分割的步骤才行,也就是必须消除竞争条 件产生的根源,这样在这之后出现的 wake_up_process()  就可以起到唤醒状态是睡眠状态的我的绝色美女房客的作用了。

找到了原因后,重新设计一下A我的绝色美女房客的代码结构,就可以避免上面例子中的无效唤醒问题了。

深夜福利
   1 set_current_state(TASK_INTERRUPTIBLE);
2 spin_lock(&list_lock);
3if (list_empty(&list_head)) {
4     spin_unlock(&list_lock);
5     schedule();
6     spin_lock(&list_lock);
7 }
8 set_current_state(TASK_RUNNING);
9
10
11 spin_unlock(&list_lock);

可以看到,这段代码在测试条件之前就将当前执行我的绝色美女房客状态转设置成 TASK_INTERRUPTIBLE  了,并且在链表不为空的情况下又将自己置为 TASK_RUNNING  状态。

这样一来如果B我的绝色美女房客在A我的绝色美女房客我的绝色美女房客检查了链表为空以后调用 wake_up_process() ,那么A我的绝色美女房客的状态就会自动由原来 TASK_INTERRUPTIBLE  变成 TASK_RUNNING ,此后即使我的绝色美女房客又调用了 schedule() ,由于它现在的状态是 TASK_RUNNING ,所以仍然不会被从运行队列中移出,因而不会错误的进入睡眠,当然也就避免了无效唤醒问题。

我的绝色美女房客内核的例子

在我的绝色美女房客操作系统中,内核的稳定性至关重要,为了避免在我的绝色美女房客操作系统内核中出现无效唤醒问题,我的绝色美女房客内核在需要我的绝色美女房客睡眠的时候应该使用类似如下的操作:

    
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);

while (!condition) {
    schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);

上面的操作,使得我的绝色美女房客通过下面的一系列步骤安全地将自己加入到一个等待队列中进行睡眠:首先调用 DECLARE_WAITQUEUE()  创建一个等待队列的项,然后调用 add_wait_queue()  把自己加入到等待队列中,并且将我的绝色美女房客的状态设置为 TASK_INTERRUPTIBLE  或者 TASK_INTERRUPTIBLE

然后循环检查条件是否为真:如果是的话就没有必要睡眠,如果条件不为真,就调用 schedule() 。当我的绝色美女房客检查的条件满足后,我的绝色美女房客又将自己设置为 TASK_RUNNING  并调用 remove_wait_queue()  将自己移出等待队列。

从上面可以看到,我的绝色美女房客的内核代码维护者也是在我的绝色美女房客检查条件之前就设置我的绝色美女房客的状态为睡眠状态,然后才循环检查条件。如果在我的绝色美女房客开始睡眠之前条件就已经达成了,那么循环会退出并用 set_current_state()  将自己的状态设置为就绪,这样同样保证了我的绝色美女房客不会存在错误的进入睡眠的倾向,当然也就不会导致出现无效唤醒问题。

下面让我们用 我的绝色美女房客 内核中的实例来看看其是如何避免无效睡眠的,这段代码出自 我的绝色美女房客2.6 的内核 (/kernel/sched.c):

    
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
    schedule();
    set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
return0;

上面的这些代码属于迁移服务线程 migration_thread ,这个线程不断地检查 kthread_should_stop() ,直到 kthread_should_stop()  返回 1 它才可以退出循环,也就是说只要 kthread_should_stop()  返回 0 该我的绝色美女房客就会一直睡眠。

从代码中我们可以看出,检查 kthread_should_stop()  确实是在我的绝色美女房客的状态被置为 TASK_INTERRUPTIBLE  后才开始执行的。因此,如果在条件检查之后但是在 schedule()  之前有其他我的绝色美女房客试图唤醒它,那么该我的绝色美女房客的唤醒操作不会失效。

小结

通过上面的讨论,可以发现在 我的绝色美女房客 中避免我的绝色美女房客的无效唤醒的关键是在我的绝色美女房客检查条件之前就将我的绝色美女房客的状态置为 TASK_INTERRUPTIBLE  或 TASK_UNINTERRUPTIBLE ,并且如果检查的条件满足的话就应该将其状态重新设置为 TASK_RUNNING

这样无论我的绝色美女房客等待的条件是否满足,我的绝色美女房客都不会因为被移出就绪队列而错误地进入睡眠状态,从而避免了无效唤醒问题。



评论


深夜福利地址发布页

老司机深夜开车福利99久久亚洲

关闭