在Linux中, 一个等待队列由一个"等待队列头"来管理,等待队列是双向链表结构。 应用场合:将等待同一资源的进程挂在同一个等待队列中。
数据结构
在include/linux/wait.h
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;//定义wait_queue_head_t结构类型:一个等待队列的头结构表征一条等待队列
等待队列的操作函数:
1.声明和初始化
动态的方法:
wait_queue_head_t my_queue; //先声明
init_waitqueue_head(&my_queue);//接着初始化它
静态的方法:
DECLARE_WAIT_QUEUE_HEAD(name);//定义并初始化等待队列(头)
2.定义等待队列项
DECLARE_WAITQUEUE(name, tsk); //只是等待队列中的一项而已哦。
3.添加删除等待项
//添加到等待队列中去之后,不会进入睡眠等待
void fastcall add_wait_queue(wait_queue_head_t * q, wait_queue_t * wait);
//删除唤醒以后的等待项
void fastcall remove_wait_queue(wait_queue_head_t * q, wait_queue_t * wait);
4.等待时间操作(宏函数)
①只能被wake_up唤醒,不能被中断信号唤醒的:醒来的第一件事情就是检查condition条件,如果为真,立马起床,否则继续睡觉。
wait_event(queue, condition);
②最常用的可被中断信号唤醒的等待队列: 被中断信号唤醒之后,立马起床,但是: 如果condition=0 -> 返回-ERESTARTSYS错误码;如果condition=1 -> 返回0
wait_event_interruptible(queue, condition);
③如果睡眠期间被wake_up唤醒后,如果condition为真:立马“起床”,返回0;否则,继续睡觉,直到超时才“起床”并返回0;
wait_event_timeout(queue, condition, timeout);
④可想而知
wait_event_interruptible_timeout(queue, condition, timeout);
5.唤醒等待队列头牵引的所有项
①可唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERUPTIBLE状态的进程,和wait_event/wait_event_timeout成对使用
void wake_up(wait_queue_head_t * queue);
②只能唤醒TASK_INTERRUPTIBLE状态的进程.,与wait_event_interruptible/wait_event_interruptible_timeout成对使用
void wake_up_interruptible(wait_queue_head_t * queue);
6.在等待事件中睡眠
①把目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列元素,之后把他附属到等待队列头q,直到资源可用,q引导的等待队列被唤醒
void sleep_on(wait_queue_head_t *q); // 只能被wake_up()宏唤醒
②将进程状态置为TASK_INTERRUPTIBLE.......
问题思考:
问1.“在等待队列中睡眠”与“等待事件”的区别是什么?
答1.区别是“在等待队列中睡眠”不需要condition参数,调用wake_up()或wake_up_interruptible()就唤醒队列上的所有等待......
问2.内核中中的“阻塞与非阻塞”和“并发控制”有什么区别?
答2.