等待队列

工作队列和等待队列的区别

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

  1. DECLARE_WAITQUEUE(name, tsk) 创建一个等待队列:
    tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.
  2. 将等待队列头 加入/移除 等待队列:
        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);
  1. 设置进程状态:
set_current_state(TASK_INTERRUPTIBLE) 等

4.进程调度:

        schedule() 或者 schedule_timeout()

进程状态

TASK_INTERRUPTIBLE 与 TASK_UNINTERRUPTIBLE 区别在于,

它的休眠是否会被信号打断,别的进程发来一个信号比如 kill ,TASK_INTERRUPTIBLE 就会醒来去处理。然而 TASK_UNINTERRUPTIBLE 不会。schedule(),进程调度,而schedule_timeout()进行调度之后,一定时间后自动唤醒

你可能感兴趣的:(等待队列)