在现代软件开发中,我们经常需要同时处理多个任务。为了更高效地管理这些任务,我们需要一种工具来帮助它们有序运行。这时候,"并发管理工作队列"就派上用场了。
一、工作队列的实现
在使用工作队列时,流程通常分为三步:
- 先定义一个任务项(work)
- 把任务添加到任务队列(workqueue)里
- 工作线程(后台线程)会自动执行队列里的任务
当有新任务加入队列时:
- 工作线程会取出并执行所有待处理的任务
- 执行完毕后线程会暂停等待
- 等到有新任务加入队列时,线程再次被唤醒执行
二、什么是并发管理工作队列
传统的工作队列在处理任务时存在明显不足。无论是单核还是多核系统,都存在两个主要问题:一是无法充分发挥多核处理器的性能,二是无法公平处理不同优先级的任务。为了解决这些问题,Con Kolivas 提出了名为"并发管理工作队列"(CMWQ)的解决方案。
形象理解
CMWQ 就像一家繁忙餐厅的点餐系统。所有点餐请求都会放进一个共享的"任务队列"里,多个服务员可以同时从队列里领取任务,独立完成自己的服务工作。
CMWQ 的核心设计就是通过这种"多人同时取任务"的机制,让系统资源得到最佳利用:
- 充分利用所有服务员的能力(就像多核处理器的每个核心都能被用上)
- 任务分配更公平(不同优先级的订单可以被合理安排)
- 整个系统运行效率更高
三、并发管理工作队列接口函数
Linux 内核中的 alloc_workqueue 函数用来创建工作队列:
c
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active);1
参数解释:
fmt:设置工作队列的名字格式flags:通过标志位控制队列行为,例如WQ_UNBOUND表示不绑定 CPU,WQ_HIGHPRI表示高优先级等max_active:设定队列中同时处理的工作项最大数量
函数会返回指向工作队列结构体的指针,若创建失败则返回 NULL。
四、实验程序
源代码下载
bash
git clone git@gitee.com:yangxuesong314/linux-driver.git1
- 若之前已 git 拉取代码可以忽略
- 代码位于:
linux-driver/04.中断及异常/06.并发管理工作队列实验
实验说明
- GPIO1_A4 →
1 * 32 + 0 * 8 + 4 = 36
Makefile:
makefile
export ARCH=arm64
export CROSS_COMPILE=/home/book/rk/tspi/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
obj-m += interrupt.o
KDIR := /home/book/rk/tspi/kernel
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
驱动代码:
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(36);
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");1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
驱动加载:insmod interrupt.ko

拉高 GPIO:
