Table of Contents
什么是workqueue
Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。
工作队列(workqueue)是另外一种将工作推后执行的形式.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。最重要的就是工作队列允许被重新调度甚至是睡眠。
内核里一直运行类似worker thread
,它会对工作队列中的work
进行处理,大致的工作流程原理可以参考下图所示;:
也就是一个线程管理多个工作任务
两种形式的工作队列
#include <linux/include/workqueue.h>
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
work_struct 通知内核线程,在后续的时间里,系统将会自动调用work结构体对应的func函数
struct delayed_work {
struct work_struct work;
struct timer_list timer;
/* target workqueue and CPU ->timer uses to queue ->work */
struct workqueue_struct *wq;
int cpu;
};
delay_work 该工作队列里拥有一个timer定时器结构体,从而实现延时工作
编程步骤
1、初始化
struct work_struct btn_work:
INIT_WORK(&btn_work, btn_work_func); //指定工作的处理函数
struct delayed_work btn_dwork:
INIT_DELAYED_WORK(&btn_dwork, btn_dwork_func); //指定延时工作的处理函数
2、登记调度
struct work_struct btn_work
schedule_work(&btn_work); //登记工作,内核会将这个工作交给内核默认的线程管理
struct work_struct btn_work
//登记延时的工作,并且指定延时的工作处理函数是5秒以后去执行。如果延时时间还没有到期,由重新登记,
schedule_delayed_work(&btn_dwork, 5*HZ);
参考代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
//定义按键硬件相关的数据结构
struct button_resource {
int irq; //中断号
char *name; //中断名称
};
//初始化按键信息
static struct button_resource btn_info[] = {
[0] = {
.irq = IRQ_EINT(0),
.name = "KEY_UP"
},
[1] = {
.irq = IRQ_EINT(1),
.name = "KEY_DOWN"
}
};
//分配工作和延时工作
static struct work_struct btn_work;
static struct delayed_work btn_dwork;
//工作处理函数
static void btn_work_func(struct work_struct *work)
{
printk("%s: %#x\n", __func__, work);
}
//延时工作处理函数
static void btn_dwork_func(struct work_struct *work)
{
printk("%s: %#x\n", __func__, work);
}
//中断处理函数就是顶半部
static irqreturn_t button_isr(int irq, void *dev_id)
{
//登记工作,内核会在适当的时候执行工作对应的处理函数
//schedule_work(&btn_work);
//登记延时工作,并且指定延时的时间间隔为3S
schedule_delayed_work(&btn_dwork, 3*HZ);
printk("%s\n", __func__);
return IRQ_HANDLED; //处理完毕
}
static int btn_init(void)
{
int i;
printk("register irq!\n");
for (i = 0; i < ARRAY_SIZE(btn_info); i++)
request_irq(btn_info[i].irq, button_isr,
IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,
btn_info[i].name, &btn_info[i]);
//初始化工作和延时的工作
INIT_WORK(&btn_work, btn_work_func); //指定工作处理函数
INIT_DELAYED_WORK(&btn_dwork, btn_dwork_func); //指定延时工作处理函数
printk("%s: %#x, %#x\n",
__func__, &btn_work, &btn_dwork);
return 0;
}
static void btn_exit(void)
{
int i;
printk("unregister irq!\n");
//注意注册中断传递的参数和释放中断传递的参数一定要一致!
for(i = 0; i < ARRAY_SIZE(btn_info); i++)
free_irq(btn_info[i].irq, &btn_info[i]);
}
module_init(btn_init);
module_exit(btn_exit);
MODULE_LICENSE("GPL");