等待队列
2018-09-04 本文已影响0人
gbmaotai
工作队列和等待队列的区别
1.work queue
是一种bottom half,中断处理的后半程,强调的是动态的概念,即work是重点,而queue是其次。
create_singlethread_workqueue
queue_work
2.wait queue
是一种「任务队列」,可以把一些进程放在上面睡眠等待某个事件,强调静态多一些,重点在queue上,即它就是一个queue,等待队列是一种实现阻塞和唤醒的内核机制.
睡眠是“自愿调度”,其实就是将当前进程的状态设置为 TASK_INTERRUPTIBLE 等状态,然后schedule() 让出CPU1,让调度器重新选择一个进程来执行。
TASK_INTERRUPTIBLE
schedule()
等待队列
其他进程为了能够唤醒休眠的进程,它必须知道休眠的进程在哪里,出于这样的原因,需要有一个称为等待队列的结构体。等待队列是一个存放着等待某个特定事件进程链表。
定义并初始化一个链表。以后就能够在这个链表添加需要等待的进程了。
等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头(wait queue head),等待队列头是一个类型为wait_queue_head_t的数据结构
a、等待队列头
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
b、等待队列
struct __wait_queue {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
clipboard.png
等待队列的使用
1、定义初始化等待队列头以及将条件置成假(condition = 0)。
静态定义初始化
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.task_list = { &(name).task_list, &(name).task_list }}
动态定义初始化
wait_queue_head_t test_queue; //1、定义等待队列头
//初始化等待队列头,注意函数调用的位置
init_waitqueue_head(&my_dev.test_queue);
//它必须在cdev添加函数”cdev_add”前。因为”cdev_add”执行成功就意味着设备可以被操作,设备被操作前当然需要把所有的事情都干完,包括等待队列的初始化。
2、在需要阻塞的地方调用wait_event()函数,使进程进入睡眠,将控制权释放给调度器。在wait_event()函数的后面需要将条件置成假(condition = 0)。
if(wait_event_interruptible(dev->test_queue, dev->cur_size > 0))
return - ERESTARTSYS;
wait_event(queue, condition)
wait_event_interruptible(queue, condition)
wait_event_timeout(queue, condition, timeout)
wait_event_interruptible_timeout(queue, condition, timeout)
3、当条件满足时,在内核的另一处,先将条件置成真(condition = 1),然后调用wake_up()函数唤醒等待队列中的睡眠进程。
wake_up_interruptible(&dev->test_queue);
你调用 wake_up 去唤醒一个使用 wait_event 等,进入休眠的进程,唤醒之后,它会判断 condition 是否为真,如果还是假的继续睡眠。
手动睡眠,没有condition
- DECLARE_WAITQUEUE(name, tsk) 创建一个等待队列:
tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列. - 将等待队列头 加入/移除 等待队列:
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
- 设置进程状态:
set_current_state(TASK_INTERRUPTIBLE) 等
4.进程调度:
schedule() 或者 schedule_timeout()
进程状态
TASK_INTERRUPTIBLE 与 TASK_UNINTERRUPTIBLE 区别在于,
它的休眠是否会被信号打断,别的进程发来一个信号比如 kill ,TASK_INTERRUPTIBLE 就会醒来去处理。然而 TASK_UNINTERRUPTIBLE 不会。schedule(),进程调度,而schedule_timeout()进行调度之后,一定时间后自动唤醒