在linux的内核中,有很多睡眠相关的函数,比如sleep_on,当然也有wake_up,睡眠的意义就是不能再运行了,那么睡眠总要有个地方啊,我们睡眠都要有个床,按照人性化设计出来的linux内核也应该有个睡眠用的床,这是对的,但是,睡眠一定要在床上吗?非也!
就好像现代的白领们,习惯就很不好,总喜欢伏案而小憩,这样不但不解乏而且还不利于健康,不管怎么说也算是一个休息方式,另外闲着没啥事的时候也会这样,但是躺在床上的睡眠一般都是必须的睡眠,而且都是确定的,不是临时的,比如如果你想睡上一觉,那么你就要上床,正好和伏案相反,伏案的意义是当时不是你睡觉的时间,只是万不得已了,太困了才勉强这样的,这些人要么是自己作的,要么就是人民的公仆,很累的那种。我们看一下linux内核中进程的睡眠,也就是这两种,一种是睡眠在队列,另一种就是睡眠在原地,其中第一种睡眠在队列就是:
static long __sched sleep_on_common(wait_queue_head_t *q, int state, long timeout)
{
unsigned long flags;
wait_queue_t wait;
init_waitqueue_entry(&wait, current); //先给这个进程铺张床
__set_current_state(state); //要睡了
spin_lock_irqsave(&q->lock, flags);
__add_wait_queue(q, &wait); //把床搬到一个统一的睡觉的地方
spin_unlock(&q->lock);
timeout = schedule_timeout(timeout); //睡吧
spin_lock_irq(&q->lock);
__remove_wait_queue(q, &wait); //醒了之后把床搬离睡觉的宿舍
spin_unlock_irqrestore(&q->lock, flags);
return timeout;
}
往往这种睡眠的都是一些默默无闻的进程,它们遇到一种特殊情况必须要睡一会,因为除此之外没有别的事情要它们做了,比如要获得一个资源,但是又获取不到,那么就只能睡觉了,linux内核用这种方式管理这大量的进程以使得不会发生暴动和混乱,linux内核为每一种可能的资源都安排了一个宿舍,也就是一个睡眠队列,然后哪个进程由于这个资源需要睡眠,就搬到这间宿舍来睡一会,如果资源可以满足了,那么就是把所有睡着的进程全部唤醒,让它们一起来竞争资源,linux内核也只能用这种方式来兼顾公平了,这样大家都没有意见,毕竟内核不可能记住每一个进程的名字来纷纷唤醒它们,因为它们很平淡,只能这样。
那么还有一种进程可以随意睡眠,只要它们想睡就可以,这种进程一般都是内核守护线程,往往是完成一些重要又特殊工作的内核线程,内核当然会记住它们每一个的名字了,它们睡眠就不需要特定的宿舍了,比如pdflush线程会这么做:
for ( ; ; ) {
struct pdflush_work *pdf;
set_current_state(TASK_INTERRUPTIBLE); //要睡了
...
schedule(); //直接睡眠
...
(*my_work->fn)(my_work->arg0); //被唤醒以后执行工作
...
}
毕竟这些内核线程一直运行,它们很累,又不能回家休息,那么就只能伏案而小憩了,当内核需要它们工作时,因为内核记着它们的名字,于是直接将它们唤醒就是了。另外还有一种进程,虽然在集体宿舍登记了要睡眠了,但是事实上却只在那里挂个名字,并不真睡,而是马上出门继续工作,内核当然不反对了,当内核要唤醒宿舍的进程们时,还将包括它的名字,内核只按照名字唤醒而不管该进程真的在干什么,比如异步过程(AIO)就是这样的进程,这种异步的过程在阻塞在资源的时候登记完睡眠名单后要马上去做别的事情。
实际上,linux内核中睡眠,睡眠队列以及调度是不会相互影响的,你完全可以在睡眠队列而不真正睡眠,也可以睡眠了但是不在任何队列,到底怎样,就看编程者的策略了。
linux中的睡眠
最新推荐文章于 2024-08-14 15:09:27 发布