news 2026/2/8 22:33:51

阻塞 IO 实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
阻塞 IO 实验
什么是等待队列
在 Linux驱动程序中,阻塞进程可以使用等待队列来实现。等待队列是实现阻塞和唤醒的
内核机制,等待队列以双循环链表为基础结构,其中链表头和链表项两部分别表示等待队列头
和等待队列元素,如图所示。
等待队列使用方法
步骤一:初始化等待队列头,并将条件置成假(condition=0)
步骤二:在需要阻塞的地方调用wait_event(),使进程进入休眠状态。
步骤三:当条件满足时,需要解除休眠,先将条件设置成真(condition=1),然后调用wake_up()
函数唤醒等待队列中的休眠进程。
实验代码wq.c
#include <linux/cdev.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/io.h> #include <linux/kdev_t.h> #include <linux/module.h> #include <linux/uaccess.h> #include <linux/wait.h> struct device_test { dev_t dev_num; // 设备号 int major; // 主设备号 int minor; // 次设备号 struct cdev cdev_test; // cdev struct class *class; // 类 struct device *device; // 设备 char kbuf[32]; int flag; // 标志位 }; struct device_test dev1; DECLARE_WAIT_QUEUE_HEAD(read_wq); // 声明等待队列头 /*打开设备函数*/ static int cdev_test_open(struct inode *inode, struct file *file) { file->private_data = &dev1; // 设置私有数据 printk("This is cdev_test_open\r\n"); return 0; } /*向设备写入数据函数*/ static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct device_test *test_dev = (struct device_test *)file->private_data; if (copy_from_user(test_dev->kbuf, buf, size) != 0) { printk("copy_from_user error\r\n"); return -1; } test_dev->flag = 1; // 将条件置 1 wake_up_interruptible(&read_wq); // 唤醒等待队列中的休眠进程 return size; } /*从设备读取数据*/ static ssize_t cdev_test_read(struct file *file, char __user *buf, size_t size, loff_t *off) { struct device_test *test_dev = (struct device_test *)file->private_data; // 可中断的阻塞等待,使进程进入休眠态 wait_event_interruptible(read_wq, test_dev->flag); if (copy_to_user(buf, test_dev->kbuf, size) != 0) { printk("copy_to_user error\r\n"); return -1; } test_dev->flag = 0; // 重置标志位 return size; } static int cdev_test_release(struct inode *inode, struct file *file) { return 0; } /*设备操作函数*/ struct file_operations cdev_test_fops = { .owner = THIS_MODULE, .open = cdev_test_open, .read = cdev_test_read, .write = cdev_test_write, .release = cdev_test_release, }; static int __init chr_fops_init(void) // 驱动入口函数 { int ret; /*1 创建设备号*/ ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name"); if (ret < 0) { goto err_chrdev; } printk("alloc_chrdev_region is ok\n"); dev1.major = MAJOR(dev1.dev_num); // 获取主设备号 dev1.minor = MINOR(dev1.dev_num); // 获取次设备号 printk("major is %d \r\n", dev1.major); printk("minor is %d \r\n", dev1.minor); /*2 初始化 cdev*/ dev1.cdev_test.owner = THIS_MODULE; cdev_init(&dev1.cdev_test, &cdev_test_fops); /*3 添加一个 cdev,完成字符设备注册到内核*/ ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1); if (ret < 0) { goto err_chr_add; } /*4 创建类*/ dev1.class = class_create(THIS_MODULE, "test"); if (IS_ERR(dev1.class)) { ret = PTR_ERR(dev1.class); goto err_class_create; } /*5 创建设备*/ dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test"); if (IS_ERR(dev1.device)) { ret = PTR_ERR(dev1.device); goto err_device_create; } return 0; err_device_create: class_destroy(dev1.class); err_class_create: cdev_del(&dev1.cdev_test); err_chr_add: unregister_chrdev_region(dev1.dev_num, 1); err_chrdev: return ret; } static void __exit chr_fops_exit(void) // 驱动出口函数 { device_destroy(dev1.class, dev1.dev_num); class_destroy(dev1.class); cdev_del(&dev1.cdev_test); unregister_chrdev_region(dev1.dev_num, 1); } module_init(chr_fops_init); module_exit(chr_fops_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("topeet");
编写应用程序read.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd; char buf1[32] = {0}; char buf2[32] = {0}; fd = open("/dev/test", O_RDWR); // 打开 led 驱动 if (fd < 0) { perror("open error \n"); return fd; } printf("read before \n"); read(fd, buf1, sizeof(buf1)); // 从/dev/test 文件读取数据 printf("buf is %s \n", buf1); printf("read after \n"); close(fd); // 关闭文件 return 0; }
编写应用程序write.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { int fd; char buf1[32] = {0}; char buf2[32] = "nihao"; fd = open("/dev/test", O_RDWR); // 打开 led 驱动 if (fd < 0) { perror("open error \n"); return fd; } printf("write before \n"); write(fd, buf2, sizeof(buf2)); // 向/dev/test 文件写入数据 printf("write after\n"); close(fd); // 关闭文件 return 0; }

Makefile

export ARCH=arm64#设置平台架构 export CROSS_COMPILE=/home/alientek/rk3568_linux5.10_sdk/buildroot/output/rockchip_atk_dlrk3568/host/bin/aarch64-buildroot-linux-gnu-#交叉编译器前缀 obj-m += wq.o #此处要和你的驱动源文件同名 KDIR :=/home/alientek/rk3568_linux5.10_sdk/kernel #这里是你的内核目录 PWD ?= $(shell pwd) all: make -C $(KDIR) M=$(PWD) modules #make 操作 clean: make -C $(KDIR) M=$(PWD) clean

read应用程序进程阻塞

然后输入./write命令运行write可执行文件,如上图所示,使用write()函数向设备写入
数据,唤醒等待队列中的休眠进程。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/8 15:54:52

Linux 下驱动的编写与测试

一、驱动编写// kernel_protect.c - 最简版本 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>static int __init protect_init(void) {printk(KERN_INFO "myapp_protect: 模块加载成功\n");return 0; }static void…

作者头像 李华
网站建设 2026/2/8 17:56:54

ThinkLink 基于 RPC 的 LoRaWAN 告警通知机制

在大规模物联网系统中&#xff0c;告警能力是保障系统稳定运行的关键组成部分&#xff0c;尤其是在 LoRaWAN 等低功耗广域网络场景下&#xff0c;设备通常分散部署、长期无人值守。ThinkLink 平台基于原生 RPC 机制与触发联动模型&#xff0c;构建了一套灵活、可扩展的告警通知…

作者头像 李华
网站建设 2026/2/7 23:37:13

WT2606B屏幕驱动芯片集成语音播报和蓝牙功能在教具上的应用方案

WT2606B屏幕驱动芯片集成语音播报和蓝牙功能在教具上的应用方案在正式介绍WT2606B之前&#xff0c;我们不妨先想想&#xff1a;什么样的教具才算真正"智能"?是能显示内容就够了吗?显然不是。真正的智能教具&#xff0c;应该像一个随身携带的小老师——不仅能清晰地…

作者头像 李华
网站建设 2026/2/8 2:57:59

springboot基于Java的诊所管理系统设计实现

背景分析 医疗行业信息化需求日益增长&#xff0c;传统纸质记录和手工管理方式效率低下&#xff0c;易出错。诊所作为基层医疗机构&#xff0c;亟需通过数字化系统优化患者管理、药品库存、财务统计等核心业务流程。Java技术栈凭借稳定性、跨平台性及丰富的生态&#xff0c;成…

作者头像 李华
网站建设 2026/2/6 19:44:33

AI Agent:2026年AI生态核心,架构、A2A协议与MCP全解析(建议收藏)

文章详细介绍了AI Agent作为2026年AI生态核心的概念、架构及其关键技术组件。解析了A2A协议使不同Agent协作&#xff0c;MCP标准化协议统一工具调用&#xff0c;以及Agent Skills模块化能力的设计。这些技术共同构成了AI Agent的基础设施&#xff0c;使其能像人类一样自主决策和…

作者头像 李华
网站建设 2026/2/7 22:36:06

智谱×昇腾×昇思:自主创新算力赋能,多模态SOTA模型再迎新突破

在AI核心技术从“专用工具”向“通用智能伙伴”跨越的今天&#xff0c;全球算力升级正在支撑百万级Token的长上下文处理&#xff0c;并通过整合文本、图像、音频、视频及3D点云等多源数据&#xff0c;推动人机交互向“所见即所得”的多模态交互演进。 继谷歌发布Nano Banana Pr…

作者头像 李华