linux同步机制之wait

1. 关于 wait_event_interruptible() 和 wake_up()的使用读一下wait_event_interruptible()的源码,不难发现这个函数先将当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(),而schedule()会将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue队列中删除。从runqueue队列中删除的结果是,当前这个进程将不再参与调度,除非通过其他函数将这个进程重新放入这个runqueue队列中,这就是wake_up()的作用了。由于这一段代码位于一个由condition控制的for(;;)循环中,所以当由shedule()返回时(当然是被wake_up之后,通过其他进程的schedule()而再次调度本进程),如果条件condition不满足,本进程将自动再次被设置为TASK_INTERRUPTIBLE状态,接下来执行schedule()的结果是再次被从runqueue队列中删除。这时候就需要再次通过wake_up重新添加到runqueue队列中。如此反复,直到condition为真的时候被wake_up.可见,成功地唤醒一个被wait_event_interruptible()的进程,需要满足:在 1)condition为真的前提下,2) 调用wake_up()。所以,如果你仅仅修改condition,那么只是满足其中一个条件,这个时候,被wait_event_interruptible()起来的进程尚未位于runqueue队列中,因此不会被 schedule。这个时候只要wake_up一下就立刻会重新进入运行调度。2. 关于wait_event_interruptible的返回值根据 wait_event_interruptible 的宏定义知:1) 条件condition为真时调用这个函数将直接返回0,而当前进程不会被 wait_event_interruptible和从runqueue队列中删除。2) 如果要被wait_event_interruptible的当前进程有nonblocked pendingsignals, 那么会直接返回-ERESTARTSYS(i.e. -512),当前进程不会被wait_event_interruptible 和从runqueue队列中删除。3) 其他情况下,当前进程会被正常的wait_event_interruptible,并从runqueue队列中删除,进入TASK_INTERRUPTIBLE状态退出运行调度,直到再次被唤醒加入runqueue队列中后而参与调度,将正常返回0。附1:wait_event_interruptible  宏#define wait_event_interruptible(wq, condition)    \({                                                 \int __ret = 0;                                  \if (!(condition))                               \__wait_event_interruptible(wq, condition, __ret); \__ret;                                         \})注: C语言中{a,b, ..., x}的的值等于最后一项,即x,因此上述宏的值是 __ret。附2:wait_event_interruptible()和 wake_up的等效代码wait_event_interruptible(wq, condition) /*等效没有考虑返回值*/{if (!(condition)){wait_queue_t _ _wait;init_waitqueue_entry(&_ _wait, current);add_wait_queue(&wq, &_ _wait);for (;;){set_current_state(TASK_INTERRUPTIBLE);if (condition)break;schedule();  /* implicit call: del_from_runqueue(current)*/}current->state = TASK_RUNNING;remove_wait_queue(&wq, &_ _wait);}}void wake_up(wait_queue_head_t *q){struct list_head *tmp;wait_queue_t *curr;list_for_each(tmp, &q->task_list){curr = list_entry(tmp, wait_queue_t, task_list);wake_up_process(curr->task);/* implicit call: add_to_runqueue(curr->task);*/if (curr->flags)break;}}Linux中等待队列机制分析分类: Linux 系列 2012-01-03 21:40   210人阅读  评论(0)   收藏  举报linux任务linux内核struct任务调度list目录(?)[+]什么是等待队列?在软件开发中任务经常由于某种条件没有得到满足而不得不进入睡眠状态,然后等待条件得到满足的时候再继续运行,进入运行状态。这种需求需要等待队列机制的支持。Linux中提供了等待队列的机制,该机制在内核中应用很广泛。在Linux内核中使用等待队列的过程很简单,首先定义一个wait_queue_head,然后如果一个task想等待某种事件,那么调用wait_event(等待队列,事件)就可以了。Linux中等待队列的实现等待队列应用广泛,但是内核实现却十分简单。其涉及到两个比较重要的数据结构:1)       __wait_queue_head,该结构描述了等待队列的链头,其包含一个链表和一个原子锁,结构定义如下:struct__wait_queue_head {spinlock_tlock;struct list_headtask_list;};2)       __wait_queue,该结构是对一个等待任务的抽象。每个等待任务都会抽象成一个wait_queue,并且挂载到wait_queue_head上。该结构定义如下:struct__wait_queue {unsigned intflags;void*private;wait_queue_func_tfunc;struct list_headtask_list;};Linux中等待队列的实现思想如下图所示,当一个任务需要在某个wait_queue_head上睡眠时,将自己的进程控制块信息封装到wait_queue中,然后挂载到wait_queue的链表中,执行调度睡眠。当某些事件发生后,另一个任务(进程)会唤醒wait_queue_head上的某个或者所有任务,唤醒工作也就是将等待队列中的任务设置为可调度的状态,并且从队列中删除。

使用等待队列时首先需要定义一个wait_queue_head,这可以通过DECLARE_WAIT_QUEUE_HEAD宏来完成,这是静态定义的方法。该宏会定义一个wait_queue_head,并且初始化结构中的锁以及等待队列。当然,动态初始化的方法也很简单,初始化一下锁及队列就可以了。一个任务需要等待某一事件的发生时,通常调用wait_event,该函数会定义一个wait_queue,描述等待任务,并且用当前的进程描述块初始化wait_queue,然后将wait_queue加入到wait_queue_head中。函数实现流程说明如下:1、 用当前的进程描述块(PCB)初始化一个wait_queue描述的等待任务。2、 在等待队列锁资源的保护下,将等待任务加入等待队列。3、 判断等待条件是否满足,如果满足,那么将等待任务从队列中移出,退出函数。4、 如果条件不满足,那么任务调度,将CPU资源交与其它任务。5、 当睡眠任务被唤醒之后,需要重复(2)、(3)步骤,如果确认条件满足,退出等待事件函数。等待队列编程接口序号编程接口使用说明1wait_event这是一个宏,让当前任务处于等待事件状态。输入参数如下:@wq:等待队列@conditions:等待条件2wait_event_timeout功能与wait_event类似,多了一个超时机制。参数中多了一项超时时间。3wait_event_interruptible这是一个宏,与前两个宏相比,该宏定义的等待能够被消息唤醒。如果被消息唤醒,那么返回-ERESTARTSYS。输入参数如下:@wq:等待队列@condition:等待条件@rt:返回值4wait_event_interruptible_timeout与(3)相比,多了超时机制5wake_up唤醒等待队列中的一个任务6wake_up_all唤醒等待队列中的所有任务

(0)

相关推荐

  • 深入理解高性能网络开发路上的绊脚石 - 同步阻塞网络 IO

    linux服务器开发相关视频解析: linux下的epoll实战揭秘--支撑亿级IO的底层基石 90分钟搞懂多线程网络编程模型 在网络开发模型中,有一种非常易于开发同学使用的方式,那就是同步阻塞的网络 ...

  • linux同步机制

    很早之前就接触过同步这个概念了,但是一直都很模糊,没有深入地学习了解过,近期有时间了,就花时间研习了一下<linux内核标准教程>和<深入linux设备驱动程序内核机制>这两本 ...

  • linux 信号机制

    https://blog.csdn.net/u010765526/article/details/80085895 https://www.it610.com/article/5144432.htm ...

  • Cerebral Cortex:北师大卢春明课题组揭示亲子互动通过亲子大脑同步影响儿童认知能力的机制...

    本文来源于"北师大脑与认知科学" 在第108个母亲节即将到来之际,Cerebral Cortex 杂志于2021年4月24日在线发表了北京师范大学认知神经科学与学习国家重点实验室卢 ...

  • rsync文件同步工具常见模式有哪些?Linux命令

    互联网时代发展迅速,Linux运维技术的需求更多推进不少.市场对于Linux运维人才的需求也在逐渐加大.Linux行业崛起,在云计算大环境下,市场上对高级运维人员的需求将越来越大.文件同步工具rsyn ...

  • Linux 写时复制机制原理

    在 Linux 系统中,调用 fork 系统调用创建子进程时,并不会把父进程所有占用的内存页复制一份,而是与父进程共用相同的内存页,而当子进程或者父进程对内存页进行修改时才会进行复制 -- 这就是著名 ...

  • 亲子互动通过亲子大脑同步影响儿童认知能力的机制

    本文转自公众号:北师大脑与认知科学 在第108个母亲节即将到来之际,Cerebral Cortex杂志于2021年4月24日在线发表了北京师范大学认知神经科学与学习国家重点实验室卢春明课题组的研究论文 ...

  • Linux C 实现多线程同步的四种方式(超级详细)

    背景问题:在特定的应用场景下,多线程不进行同步会造成什么问题? 通过多线程模拟多窗口售票为例: #include <iostream> #include<pthread.h> ...

  • 由于Linux系统文件同步时突然断电导致系统进入none模式问题详解

    骚年 运维少年 一.问题概述 最近在测试公司CDM的时候遇到了这个问题,在数据同步的过程中,我对设备进行了一个快照,然后使用该快照生成了一个虚拟机,虚拟机启动时报错.报错如下: 输入root用户的密码 ...

  • linux各种通讯机制汇总

    eventfd -- 创建一个文件描述符fd,用于支持事件等待通知机制 ,  功能上类似于信号量. 使用场景:当使用pipe仅用于等待/通知功能时,可以使用eventfd替换,代价低,只需要一个文件描 ...