RK3568驱动指南|第五期-中断-第48章 并发管理工作队列实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第五期_中断_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第48章 并发管理工作队列实验

在现代的软件开发中,我们常常面临着需要同时处理多个任务的挑战。这些任务可能是并行的、独立的,或者需要以某种顺序进行处理。为了高效地管理这些并发任务,我们需要一种有效的机制来协调它们的执行。这就是并发管理工作队列发挥作用的地方。本章节我们来学习并发管理工作队列。

48.1工作队列的实现

在44章节和45章节,我们学习了共享工作队列和自定义工作队列,在使用工作队列时,我们首先定义一个work结构体,然后将work添加到workqueue(工作队列)中,最后worker thread 执行workqueue。当工作队列中有新work产生时,工作线程(worker thread)会执行工作队列中每个work。当执行完结束的时候,worker thread会睡眠,等到新的中断产生,work再继续添加到工作队列,然后工作线程执行每个工作,周而复始。

在单核线程的系统中,通常会为每个 CPU(核心)初始化一个工作线程并关联一个工作队列。这种默认设置确保每个CPU都有一个专门的线程来处理与其绑定的工作队列上的工作项。如下图(48-1)所示:

在多核线程系统中,工作队列的设计与单核线程系统有所不同。在多核线程系统中,通常会存在多个工作队列,每个工作队列与一个工作线程(Worker Thread)绑定。这样可以充分利用多个核心的并行处理能力。如下图(48-2)所示:

当有新的工作项产生时,系统需要决定将其分配给哪个工作队列。一种常见的策略是使用负载均衡算法,根据工作队列的负载情况来平衡分配工作项,以避免某个工作队列过载而导致性能下降。每个工作队列独立管理自己的工作项。当有新的工作项添加到工作队列时,工作线程会从其关联的工作队列中获取待执行的工作项,并执行相应的处理函数。在多核线程系统中,多个工作线程可以同时执行各自绑定的工作队列中的工作项。这样可以实现并行处理,提高系统的整体性能和响应速度。

了解了工作队列是如何实现的,接下来我们看看传统的工作队列有什么弊端呢?

48.2 workqueue队列弊端

假如说有三个work放到了同一个工作队列上,接下来CPU会启动工作线程去执行这三个work,如下图(48-3)所示:

在上图中,工作项w0、w1、w2被排队到同一个CPU上的绑定工作队列上。w0工作项执行的时候,先工作 5毫秒,然后睡觉10毫秒,然后再工作CPU 5毫秒,然后完成。工作项w1和w2都是工作5ms,然后睡眠10 ms,然后完成。传统工作队列的弊端如下所示:

1 在工作项w0 工作甚至是睡眠时,工作项w1 w2是排队等待的,在繁忙的系统中,工作队列可能会积累大量的待处理工作项,导致任务调度的延迟,这可能会影响系统的响应性能,并增加工作项的处理时间。

2 在工作队列中,不同的工作项可能具有不同的处理时间和资源需求。如果工作项的处理时间差异很大,一些工作线程可能会一直忙于处理长时间的工作项,而其他工作线程则处于空闲状态,导致资源利用不均衡。

3 在多线程环境下,多个工作线程同时访问和修改工作队列可能会导致竞争条件的发生。为了确保数据的一致性和正确性,需要采用适当的同步机制,如锁或原子操作,来保护共享数据,但这可能会引入额外的同步开销。

4 工作队列通常按照先进先出(FIFO)的方式处理工作项,缺乏对工作项优先级的细粒度控制。在某些场景下,可能需要根据工作项的重要性或紧急程度进行优先级调度,而工作队列本身无法提供这种级别的优先级控制。

5 当工作线程从工作队列中获取工作项并执行时,可能需要频繁地进行上下文切换,将处理器的执行上下文从一个线程切换到另一个线程。这种上下文切换开销可能会影响系统的性能和效率。

48.2 什么是并发管理工作队列

通过上一小节的学习,我们认识到传统的工作队列无论是单核系统还是多核系统上都是有缺陷的。比如无法充分利用多核处理器的计算能力以及对于不同优先级的工作项无法提供公平的调度。为了解决这些问题,Con Kolivas提出了CMWQ调度算法。

CMWQ 全称是concurrency Managed Workqueue,意为并发管理工作队列。并发管理工作队列是一种并发编程模式,用于有效地管理和调度待执行的任务或工作项。它通常用于多线程或多进程环境中,以实现并发执行和提高系统的性能。CMWQ 工作实现如下图(48-4)所示:

当我们需要在一个系统中同时处理多个任务或工作时,使用并发管理工作队列是一种有效的方式。

想象一下,你是一个餐厅的服务员,有很多顾客同时来到餐厅用餐。为了提高效率,你需要将顾客的点菜请求放到一个队列中,这就是工作队列。然后,你和其他服务员可以从队列中获取顾客的点菜请求,每个服务员独立地为顾客提供服务。通过这种方式,你们可以并发地处理多个顾客的点菜请求,而不需要等待上一个顾客点完菜再去处理下一个顾客的请求。每个服务员可以独立地从队列中获取任务,并根据需要执行相应的服务。这种独立获取任务的过程就是从工作队列中取出任务并执行的过程。

通过并发管理工作队列,你们能够更高效地处理顾客的点菜请求,提高服务的速度和质量。同时,这种方式也能够更好地利用你们的工作能力,因为每个服务员都可以独立处理任务,而不会相互干扰或等待。

总的来说,通过并发管理工作队列,我们可以同时处理多个任务或工作,提高系统的并发性和性能。每个任务独立地从队列中获取并执行,这种解耦使得整个系统更加高效、灵活,并且能够更好地应对多任务的需求。

48.3 并发管理工作队列接口函数

alloc_workqueue是Linux内核中的一个函数,用于创建和分配一个工作队列。工作队列是一种用于管理和调度工作项的机制,可用于实现并发处理和异步任务处理。alloc_workqueue函数的原型如下:

struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active);

参数说明:

fmt:指定工作队列的名称格式。

flags:指定工作队列的标志,可以控制工作队列的行为和属性,如WQ_UNBOUND表示无绑定的工作队列,WQ_HIGHPRI表示高优先级的工作队列等。

max_active:指定工作队列中同时活跃的最大工作项数量。

函数返回一个指向工作队列结构体(struct workqueue_struct)的指针,或者返回NULL表示创建失败。

在下一小节中将使用上述API进行相应的实验。

48.4 实验程序的编写

48.4.1 驱动程序编写

本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\38_CMWQ\module

本实验在35自定义工作队列实验的基础上进行修改,使用alloc_workqueue函数创建和分配一个工作队列。编写完成的interrupt.c代码如下所示,添加的代码已加粗表示。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/workqueue.h>int irq;
struct workqueue_struct *test_workqueue;
struct work_struct test_workqueue_work;// 工作项处理函数
void test_work(struct work_struct *work)
{msleep(1000);printk("This is test_work\n");
}// 中断处理函数
irqreturn_t test_interrupt(int irq, void *args)
{printk("This is test_interrupt\n");queue_work(test_workqueue, &test_workqueue_work); // 提交工作项到工作队列return IRQ_RETVAL(IRQ_HANDLED);
}static int interrupt_irq_init(void)
{int ret;irq = gpio_to_irq(101); // 将GPIO映射为中断号printk("irq is %d\n", irq);// 请求中断ret = request_irq(irq, test_interrupt, IRQF_TRIGGER_RISING, "test", NULL);if (ret < 0){printk("request_irq is error\n");return -1;}// 用于创建和分配一个工作队列test_workqueue = alloc_workqueue("test_workqueue", WQ_UNBOUND, 0);INIT_WORK(&test_workqueue_work, test_work); // 初始化工作项return 0;
}static void interrupt_irq_exit(void)
{free_irq(irq, NULL);                    // 释放中断cancel_work_sync(&test_workqueue_work); // 取消工作项flush_workqueue(test_workqueue);        // 刷新工作队列destroy_workqueue(test_workqueue);      // 销毁工作队列printk("bye bye\n");
}module_init(interrupt_irq_init);
module_exit(interrupt_irq_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");

48.5 运行测试

48.5.1 编译驱动程序

在上一小节中的interrupt.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

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

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放interrupt.c和Makefile文件目录下,如下图(图48-5)所示:

然后使用命令“make”进行驱动的编译,编译完成如下图(图48-6)所示:

 编译完生成interrupt.ko目标文件,如下图(图48-7)所示:

至此驱动模块就编译成功了,接下来进行测试。

48.5.2 运行测试

开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图48-8)所示:

insmod interrupt.ko

驱动加载之后,可以看到申请的中断号被打印了出来,然后用手触摸连接的LVDS 7寸屏幕,打印如下图(48-9)所示:

我们按一下屏幕,立即输入“ps -aux | grep test_workqueue”,可以看到工作线程,如下图(48-10)所示,u代表无绑定的工作队列。

最后可以使用以下命令进行驱动的卸载,如下图(图48-11)所示:

rmmod interrupt

至此,并发管理工作队列实验就完成了。


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

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

相关文章

【Redis学习笔记二】三种特殊数据类型、事务的基本操作、锁、持久化、发布订阅、主从复制、哨兵模式

文章目录 三种特殊数据类型geospatial 地理位置Hyperloglog 基数统计Bitmaps 事务基本操作悲观锁乐观锁 持久化RDB&#xff08;Redis Database&#xff09;AOF&#xff08;Append Only File&#xff09;拓展 Redis发布订阅命令原理缺点应用 redis主从复制概念作用为什么使用集群…

win10搭建Selenium环境+java+IDEA(3)

这里主要对前面的maven和selenium做补充说明&#xff0c;以及更新一些pom文件下载依赖的问题。 IDEA里面&#xff0c;如果你创建的工程是maven工程文件&#xff0c;那么就会有一个pom.xml文件&#xff0c;可以在这个网站&#xff1a;https://mvnrepository.com/搜索依赖&#…

【云计算网络安全】DDoS 缓解解析:DDoS 攻击缓解策略、选择最佳提供商和关键考虑因素

文章目录 一、前言二、什么是 DDoS 缓解三、DDoS 缓解阶段四、如何选择 DDoS 缓解提供商4.1 网络容量4.2 处理能力4.3 可扩展性4.4 灵活性4.5 可靠性4.6 其他考虑因素4.6.1 定价4.6.2 所专注的方向 文末送书《数据要素安全流通》本书编撰背景本书亮点本书主要内容 一、前言 云…

并发编程基础知识

一、线程的基础概念 一、基础概念 1.1 进程与线程A 什么是进程&#xff1f; 进程是指运行中的程序。 比如我们使用钉钉&#xff0c;浏览器&#xff0c;需要启动这个程序&#xff0c;操作系统会给这个程序分配一定的资源&#xff08;占用内存资源&#xff09;。 什么线程&a…

单元测试框架-Pytest(简单学习)

单元测试框架-Pytest Pytest是基于Python语言的单元测试框架&#xff0c;也是一个命令行的工具&#xff0c;比 unittest 测试框架更灵活。具有以下特点&#xff1a; 入门简单&#xff0c;易上手&#xff0c;官方文档丰富而且使用广泛&#xff0c;有大量的参数例子。 unittest…

云服务仿真:完全模拟 AWS 服务的本地体验 | 开源日报 No.45

localstack/localstack Stars: 48.7k License: NOASSERTION LocalStack 是一个云服务仿真器&#xff0c;可以在您的笔记本电脑或 CI 环境中以单个容器运行。它提供了一个易于使用的测试/模拟框架&#xff0c;用于开发云应用程序。主要功能包括&#xff1a; 在本地机器上完全…

K8S:K8S对外服务之Ingress

文章目录 一.Ingress基础介绍1.Ingress概念2.K8S对外暴露服务&#xff08;service&#xff09;主要方式&#xff08;1&#xff09;NodePort&#xff08;2&#xff09;LoadBalancer&#xff08;3&#xff09;externalIPs&#xff08;4&#xff09;Ingress 3.Ingress 组成&#x…

如何用万界星空科技低代码平台快速开发一个MES系统?

一、制造业工厂生产现状&#xff1a; 1、生产计划复杂 生产效率低&#xff0c;工作量大&#xff0c;周期长&#xff1b;生产计划执行准确性不高&#xff0c; 生产工单准时完工率过低&#xff1b;计划人员很难得到实际生产进度的准确信息&#xff1b;人员沟通成本高&#xff1…

AI工程化—— 如何让AI在企业多快好省的落地?

作为计算机科学的一个重要领域&#xff0c;机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#xff0c;帮助人们解决众多实际问题。随着机器学习技术的发展&#xff0c;越来越多的企业将机器学习技术作为核心竞争力&#xff0c;并运用在…

【图像处理】【应用程序设计】加载,编辑和保存图像数据、图像分割、色度键控研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

提取歌曲伴奏?用对软件一键帮你搞定~

相信大家经常想获取某首歌曲的伴奏&#xff0c;但是不知从何下手&#xff0c;今天这篇教程给大家分享一个超神奇软件&#xff0c;一键提取歌曲伴奏&#xff01; 第一步&#xff1a;打开【音分轨】APP&#xff0c;进入首页点击【人声分离】 第二步&#xff1a;选择导入方式&…

【Pod】

Pod 一、Pod基本概念二、Pod的使用方式pause容器&#xff08;pod的基础容器&#xff09;核心功能pause容器使得Pod中所有容器可以共享两种资源&#xff1a;网络和存储网络存储 三、Pod分类自主式Pod/静态pod控制器管理的Pod 四、三种容器五、镜像拉取策略&#xff08;image Pul…