美文网首页
等待队列

等待队列

作者: gbmaotai | 来源:发表于2018-09-04 14:37 被阅读0次

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

    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()进行调度之后,一定时间后自动唤醒

    相关文章

      网友评论

          本文标题:等待队列

          本文链接:https://www.haomeiwen.com/subject/vjbgwftx.html