linux 内核等待队列

等待队列在Linux内核中用来阻塞或唤醒一个进程,也可以用来同步对系统资源的访问,还可以实现延迟功能

在软件开发中任务经常由于某种条件没有得到满足而不得不进入睡眠状态,然后等待条件得到满足的时候再继续运行,进入运行状态。这种需求需要等待队列机制的支持。Linux中提供了等待队列的机制,该机制在内核中应用很广泛。

在Linux内核中使用等待队列的过程很简单,首先定义一个wait_queue_head,然后如果一个task想等待某种事件,那么调用wait_event(等待队列,事件)就可以了。

等待队列应用广泛,但是内核实现却十分简单。其涉及到两个比较重要的数据结构:__wait_queue_head,该结构描述了等待队列的链头,其包含一个链表和一个原子锁,结构定义如下:

struct wait_queue_head {

      spinlock_t lock;                    /* 保护等待队列的原子锁 */

      struct list_head task_list;          /* 等待队列 */

};

typedef struct wait_queue_head wait_queue_head_t;

wait_queue_entry,该结构是对一个等待任务的抽象。每个等待任务都会抽象成一个wait_queue_entry,并且挂载到wait_queue_head上。

该结构定义如下:struct wait_queue_entry {

    unsigned int flags;         //1:互斥进程,0:非互斥进程

    void *private;                       /* 通常指向当前任务控制块 */

    /* 任务唤醒操作方法,该方法在内核中提供,通常为autoremove_wake_function */

    wait_queue_func_t func;            

    struct list_head task_list;              /* 挂入wait_queue_head的挂载点 */

};

typedef struct wait_queue_entry wait_queue_entry_t;

定义"等待队列":

定义并初始化一个名为name的等待队列 ,注意此处是定义一个wait_queue_t类型的变量name,并将其private与设置为tsk

DECLARE_WAITQUEUE(name,tsk); //任务唤醒操作方法为:default_wake_function

Linux中等待队列的实现思想如下图所示,当一个任务需要在某个wait_queue_head上睡眠时,将自己的进程控制块信息封装到wait_queue_entry中,然后挂载到wait_queue_head的链表中,执行调度睡眠。当某些事件发生后,另一个任务(进程)会唤醒wait_queue_head上的某个或者所有任务,唤醒工作也就是将等待队列中的任务设置为可调度的状态,并且从队列中删除。

使用等待队列时首先需要定义一个wait_queue_head,这可以通过DECLARE_WAIT_QUEUE_HEAD宏来完成,这是静态定义的方法。该宏会定义一个wait_queue_head,并且初始化结构中的锁以及等待队列。当然,动态初始化的方法也很简单,初始化一下锁及队列就可以了。

一个任务需要等待某一事件的发生时,通常调用wait_event,该函数会定义一个wait_queue_entry,描述等待任务,并且用当前的进程描述块初始化wait_queue_entry,然后将wait_queue_entry加入到wait_queue_head中。函数实现流程说明如下:

1、  用当前的进程描述块(PCB)初始化一个wait_queue_entry描述的等待任务。

2、  在等待队列锁资源的保护下,将等待任务加入等待队列。

3、  判断等待条件是否满足,如果满足,那么将等待任务从队列中移出,退出函数。

4、 如果条件不满足,那么任务调度,将CPU资源交与其它任务。

5、 当睡眠任务被唤醒之后,需要重复(2)、(3)步骤,如果确认条件满足,退出等待事件数。

等待队列编程接口

等待队列接口函数介绍

#include <linux/wait.h> //头文件包含

1.定义一个等待队列头

wait_queue_head_t my_queue;

2.初始一个等待队列头

init_waitqueue_head(&my_queue);

定义并初始化一个等待队列头

DECLARE_WAIT_QUEUE_HEAD(my_queue);

3.进程的睡眠操作——条件睡眠

//判断condition条件,决定是否将当前进程推入等待队列(条件为假时)此函数为宏函数

wait_event(wait_queue_head_t wq, int condition);

/*可以被系统消息打断*/

wait_event_interruptible(wait_queue_head_t wq,int condition);

wait_event_timeout(wait_queue_head_t wq, int condition, long timeout);

wait_event_interruptiblble_timeout(wait_queue_head_t wq,int condition, long timeout);

参数wq:表示等待队列头

参数condition:阻塞条件,为假(0)则进入休眠直到wake_up且condition为真条件成立才退出

参数timeout:表示睡眠指定时长(时钟滴答度量,eg.延时2秒=2*HZ)后,自动转入唤醒状态

3.进程的睡眠操作——无条件睡眠(不建议使用,新内核将去掉这些接口,请使用上面的接口)

/*

 * These are the old interfaces to sleep waiting for an event.

 * They are racy.  DO NOT use them, use the wait_event* interfaces above.

 * We plan to remove these interfaces.

 */

//将当前进程推入等待队列将其睡眠,wake_up唤醒

sleep_on(wait_queue_head_t *q);

/*可以被系统消息打断*/

interruptible_sleep_on(wait_queue_head_t *q);

long sleep_on_timeout(wait_queue_head_t *q, long timeout);

long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout);

参数wq:表示等待队列头

参数timeout:表示睡眠指定时长后,自动转入唤醒状态

4.将非互斥进程插入等待队列链表的第一个位置,需要自己定义wait_queue_t

add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

函数将互斥进程插入等待队列链表的最后一个位置

add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)

5.进程唤醒函数

wake_up(wait_queue_head_t *wq);

wake_up_all(wait_queue_head_t *wq);

wake_up_interruptible(wait_queue_head_t *wq);

注意事项:

1.唤醒函数和导致睡眠函数要配对使用,如果导致睡眠函数使用带interruptible的,则唤醒函数也要使用interruptible的。

2.在使用wake_up唤醒进程之前要将wait_event中的condition变量的值赋为真,否则该进程被唤醒后会立即再次进入睡眠

3. wake_up()每次只能唤醒一个进程,而且是从队列头开始唤醒的,而wait_event()函数每次会将新建的等待队列插到队列头,因此最后调用wait_event()函数的进程先被唤醒!如果要唤醒某个特定的进程,没有现成的函数,按照本人理解,只能使用wake_up_all()函数唤醒所有进程,然后在通过条件condition来控制(每个进程使用不同的变量来控制,在wake_up_all()函数后只将要唤醒的进程的变量置成真)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全--基于Kali的网络扫描基础技术

文章目录 1. 标准ICMP扫描1.1使用Ping命令1.1.1格式1.1.2实战 1.2使用Nmap工具1.2.1格式1.2.2实战1.2.2.1主机在线1.2.2.2主机不在线 1.3使用Fping命令1.3.1格式1.3.2实战 2. 时间戳查询扫描2.1格式2.2实战 3. 地址掩码查询扫描3.1格式3.2实战 2. TCP扫描2.1TCP工作机制2.2TCP …

位运算总结

文章目录 &#x1f348;1. 基础位运算&#x1f34c;2. 给一个数n&#xff0c;确定它的二进制表示中的第x位是0还是1&#x1f34f;3. 将一个数n的二进制表示的第x位修改成1&#x1f353;4. 将一个数的n的二进制表示的第x位修改成0&#x1f954;5. 位图的思想&#x1fad2;6. 提前…

医保移动支付程序开发

作为公司最苦命的开发&#xff0c;年初接到任务开发医保移动支付程序&#xff08;微信小程序和支付宝小程序&#xff09;&#xff0c;为医疗机构提供线上医保结算。好家伙&#xff0c;我一看解压后资料大于一个G&#xff0c;内心无比的惊慌。 一、技术流程图 图太大了显示不全需…

0-1背包的初始化问题

题目链接 这道题的状态转移方程比较易于确定。dp[i][j]表示能放前i个物品的情况下&#xff0c;容量为j时能放物品的数量&#xff08;这道题歌曲数量对应物品数量&#xff0c;容量对应时间&#xff09;。 技巧&#xff08;收获&#xff09; 二维dp数组可以视情况优化为一维dp数组…

Linux——vim编辑文件时——.swp文件解决方案

test.cpp样例 当我们vim test.cpp进入编辑文件。 却忘记了保存退出 再次进入就会出现一下画面 当你摁下Enter键位 出现以下几个选项 O——是只读不写 E——是正常打开文件但不会载入磁盘内容 R——覆盖——是加载存储磁盘的文件(当我们忘记保存时&#xff0c;系统会自动帮我…

事件代理?

1.什么是事件代理&#xff1f; 事件代理也叫事件委托&#xff0c;只指定一个事件处理程序&#xff0c;就可以管理某一类型得事件。 可以简单理解为&#xff0c;事件代理就是将本应该绑定子元素事件绑定给父元素代理。它的优点就是&#xff1a;减少事件得执行&#xff0c;减少浏…

CentOS 7 部署 MariaDB 的 2 种方法

有两种安装 MariaDB 服务器的方法。您可以安装 CentOS 7 存储库中可用的默认版本&#xff0c;也可以通过手动添加 MariaDB 存储库来安装最新版本。 如果安装过MariaDB或MySQL&#xff0c;使用以下命令彻底删除它们: yum remove mariadb* yum remove mysql* 方法一: 使用 Yum…

Make Pixels Dance: High-Dynamic Video Generation论文解析

高动态视频生成的新进展 Make Pixels Dance: High-Dynamic Video Generation高动态视频生成的新进展前言视频生成模式摘要论文十问实验数据集定量评估指标消融研究 训练和推理技巧训练技术推理技术 更多的应用 Make Pixels Dance: High-Dynamic Video Generation 高动态视频生…

VBA技术资料MF87:创建固定顺序名称的一组文件夹

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

gRPC Java、Go、PHP使用例子

文章目录 1、Protocol Buffers定义接口1.1、编写接口服务1.2、Protobuf基础数据类型 2、服务器端实现2.1、生成gRPC服务类2.2、Java服务器端实现 3、java、go、php客户端实现3.1、Java客户端实现3.2、Go客户端实现3.3、PHP客户端实现 4、运行效果 本文例子是在Window平台测试&a…

Unity UGUI图片锯齿严重怎么解决

在开发的时候&#xff0c;发现图片锯齿严重&#xff0c;打包到移动端或者在编辑器都这样&#xff0c;如下图 原因&#xff1a; 查了一些资料&#xff0c;找到了原因如下&#xff1a;关于为什么会发生这种情况&#xff1a;看起来你的源资源比你在屏幕上显示的大小大得多。所以当…

深入浅出 Vue 中的插槽 slot

深入浅出 Vue 中的插槽 slot start 最近被问到好几次 Vue 中的插槽相关知识&#xff0c;掌握的还是有些不全面。抱着重新学习的心态&#xff0c;写这篇博客。首先对基础知识做一个回顾&#xff0c;然后再对源码实现做一个学习。作者&#xff1a;番茄编写时间&#xff1a;2023…

STM32_10(I2C)

I2C通信 I2C&#xff08;Inter IC Bus&#xff09;是由Philips公司开发的一种通用数据总线两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;、SDA&#xff08;Serial Data&#xff09;同步&#xff0c;半双工带数据应答支持总线挂载多设备&#xff08;一主多从…

QAC支持的静态度量属性

上面介绍了Coverity支持的12个度量属性&#xff0c;下面我们看看QAC这款工具支持的度量属性。下面分成3类&#xff0c;函数度量、文件度量和类度量。 函数度量指标不多&#xff0c;一共有8个。 文件度量度量指标一共10个&#xff0c;如下表。 类度量指标一个8个&#xff0c;如…

python实现C++简易自动压行

突发奇想&#xff0c;想要将自己的c压行之后交上去。但是苦于手动压行效率太低&#xff0c;在网上搜索压行网站没有找到&#xff0c;突然发现压行不就是检查检查去个换行符吗。于是心血来潮&#xff0c;用python实现了一个简易压行程序。 首先&#xff0c;宏定义等带#的文件不…

正则表达式及文本三剑客grep,awk,sed

目录 正则表达式 前瞻 代表字符 表示次数 位置锚定 分组或其他 grep 选项 范例 awk 前瞻 awk常见的内置变量 范例 sed 前瞻 sed格式 范例 搜索替代 格式 范例 分组后项引用 格式 范例 正则表达式 前瞻 通配符&#xff1a;匹配的是文件名 正则表达式&a…

Windows10免安装PostgreSQL

1. PostgreSQL简介2. 下载3. 安装环境4. 安装 4.1. 初始化数据库4.2. 启动数据库4.3. 注册服务4.3. 卸载服务 1. PostgreSQL简介 PostgreSQL 是一种特性非常齐全的自由软件的对象-关系型数据库管理系统&#xff0c;是以加州大学计算机系开发的 POSTGRES 4.2版本为基础的对象关…

java开发需要掌握的maven相关知识和Junit单元测试

maven简介 什么是maven&#xff1a; maven是一款管理和构建java项目的工具&#xff0c;是apache旗下的一个开源项目。 maven的作用&#xff1a; 依赖管理&#xff1a; 方便快捷的管理项目依赖的资源&#xff08;jar包&#xff09;。 项目构建&#xff1a; 标准化的跨平台&#…

开发知识点-CSS样式

CSS样式 fontCSS 外边距 —— 围绕在元素边框的空白区域# linear-gradient() ——创建一个线性渐变的 "图像"# transform ——旋转 元素![在这里插入图片描述](https://img-blog.csdnimg.cn/20191204100321698.png)# rotate() [旋转] # 边框 (border) —— 围绕元素内…

计算机毕业设计php+bootstrap小区物业管理系统

意义&#xff1a;随着我国经济的发展和人们生活水平的提高&#xff0c;住宅小区已经成为人们居住的主流&#xff0c;人们生活质量提高的同时&#xff0c;对小区物业管理的要求也越来越高&#xff0c;诸如对小区的维修维护&#xff0c;甚至对各项投诉都要求小区管理者做得好&…