等待队列介绍:
等待队列可以让进程进入休眠等待状态。
等待队列, 例如,在字符设备的读状态当中,如果没有可读的字符, 那么进程可以进入休眠等待状态,条件满足以后,唤醒进程。
在写操作当中,如果缓冲区满了,进程也可以进入等待状态,等有空间以后再唤醒进程进行写的操作。
休眠对进程意味着,它会被标记为一种特殊的状态,并从调度器中把运行的队列移走。
在某个时刻这个状态发生改变了以后,进程才会在任意的cpu上调度。
在让进程休眠时,我们需要注意自己的代码。。。
a:不要在原子上下文中进入休眠,也就是说,不要在进程拥有自旋锁,seqlock,RCU时进入休眠。
在禁止中断的情况下也不能进入休眠,而在拥有信号量时进入休眠是可以的,但是在其他的线程当中,如果有
现在在获取这个信号量,那么这个线程也会进入休眠(因为这个线程获取不到信号量嘛,所以也进入休眠了)
b:在唤醒进程以后我们不对进程的状态做任何的判断,因为也有可能有其他的进程在唤醒了以后把我们的资源拿走。。所以最好不要做这种判断。
c:我们必须知道,进入休眠的进程,我们的代码可能会在程序的那些地方唤醒它。
所以在ldd3里面,等待队列的意思被解释为,需要维护一个数据结构(也就是等待队列),它能够帮助我们知道休眠的进程。
也就是说,等待队列就是一个进程列表,其中包含了等待某个特定事件的所有进程。
等待队列通过等待队列头(wait queue head)来管理。
需要包含的头文件: #include<linux/wait.h>
初始化方式:
(1)DECLARE_WAIT_QUEUE_HEAD(wq)
(2)wait_queue_head_t wq; init_waitqueue_head(&wq)
内核里面等待队列的数据结构。
struct wait_queue_head {
spinlock_t lock;
struct list_head head;
};
typedef struct wait_queue_head wait_queue_head_t;
进入等待状态(进程的简单休眠):
(1)wait_event(wq); 不可打断,进程满足条件进入D+状态
#define wait_event(wq_head, condition) \
do { \
might_sleep(); \
if (condition) \
break; \
__wait_event(wq_head, condition); \
} while (0)
(2)wait_event_interruptible(wq);可发信号进行打断,进入进入休眠后是S+状态
(3)wait_event_timeout(queue, condition,timeout);
(4)wait_event_interruptible_timeout(queue, condition,timeout);
3和4都是在某个时间段以后会唤醒进程。
唤醒的地方可能在某个线程或者进程,中断里。
唤醒等待状态:
(1)wake_up(wait_queue_head_t *queue);
这个函数会唤醒在给定的等待队列上的所有进程。
(2)wake_up_interruptible(wait_queue_head_t *queue);
这个函数会唤醒在给定队列上那些执行可中断的进程。
我们一般的做法就是在使用时进行配对使用。如,wait_event与wake_up,wait_event_interruptiable与wake_up_interruptible。