liux等待队列的使用场景是什么(liux等待队列的使用场景在哪)
导语:linux等待队列的使用场景
1) 为什么要用等待队列?
假设我们在 kernel 里产生一个 buffer,user 可以经由 read,write 等 system call 来读取或写资料到这个 buffer 里。如果有一个 user 写资料到 buffer 时,此时 buffer 已经满了。那请问你要如何去处理这种情形呢?
我们可能会想到使用一个状态位if_full来判断当前是否可以执行write_to_buffer,并且建立一个任务线程通过无限循环不断的检测这个状态位,当其他线程将这个标志位置位后,任务线程便会开始执行任务。
while ( is_full );
write_to_buffer;
2) 这样做可行吗?
在用户空间里使用while(1)系统会自动调度使其他进程也能够执行,但如果在内核空间里使用while(1)则如果该处于内核空间的线程自己不打断自己或者没有外部SIGNAL(例如kill)来打断则会一直这样循环下去。这样做其他线程都会被卡住,相当于死机。
等待队列常用于这种内核空间不断检测一个状态位并根据状态位执行任务的线程
1.初始化等待队列头
init_waitqueue_head(wait_q)
2.负责执行任务的任务线程在等待队列wait_q没有被唤醒且状态位is_full不满足条件时,一直处于睡眠状态
while(1)
{
if(wait_event_interruptible(wait_q,is_full))
{
//执行任务
}
}
3.另一线程在需要让任务线程执行任务时调用wake_up将处于等待队列中的任务线程唤醒,调用wake_up后如果if_full状态位不满足条件,则任务线程不会被真正的唤醒,继续进入睡眠
wake_up_interruptible(wait_q)
如果在用户空间使用等待队列这种机制,提高了cpu使用效率。内核空间遇到while循环这种情况则必须使用等待队列
3) wait_event内部框架是什么?
DECLEARE_WAITQUEUE(wait,current);//初始化一个等待队列wait
add_wait_queue(q,&wait);//将wait加入等待队列q
while(!conditon)//condition就是线程被唤醒的条件
{
set_current_state(TASK_INTERRUPTIBLE);//设置当前线程可以被信号打断
If ( signal_pending( current ) )
{
iret = -ERESTARTSYS;
break;
}
schedule();//使当前线程睡眠,内核去调度其他线程
}
set_current_state(TASK_RUNNING);//条件
remove_wait_queue(q,&wait);
这就相当于内核每次调度到这里,发现不满足条件都会继续执行调度,让这个线程继续睡眠,如果状态位改变了,那么下次调度到这里时就会跳出while循环,并且设置线程运行状态为TASK_RUNNING并且将wait移出等待队列q,这时这个线程才算真正的被唤醒。
设置为TASK_RUNNING,并不是这个进程马上被执行,而是在运行队列中,根据优先级等进程调度规则,进程调度执行。
将wait移出q,相当于其他线程再调用wake_up时就跟当前这个任务线程没关系了
4) 关于
if ( signal_pending( current ) )
{
iret = -ERESTARTSYS;
break;
}
陷入内核态的进程不会被信号打断,如果内核态里有无限循环,则永远无法跳出内核态,此时就需要内核态进程自己检测信号来跳出内核空间。
执行signal_pending来检查当前进程是否有信号需要处理,如果有则返回-ERESTARTSYS,之后从内核空间转到用户空间去执行信号处理函数,同时当内核态系统调用返回-ERESTARTSYS后,上层库函数会根据这个返回值重启这个系统调用。
本文内容由小纳整理编辑!