29.1 前言
Linux中的工作队列是将工作推后执行的一种方式,通常用在中断分层机制中,因为中断函数的原则是(1)快;(2)不能睡眠或等待;因此,在中断驱动程序中,引入工作队列实现中断的分层,硬件处理在中断函数中处理,软件及其耗时操作则在Linux内核线程中实现。本小节,将介绍Linux内核队列及其使用方式。
29.2 工作队列特点
(1)工作队列中是可以阻塞或睡眠的;
(2)调用schedule_work(&work)后,work马上就会被调度执行;
(3)Linux工作队列属于一种异步处理机制;
(4)工作队列是通过内核进程实现的;
29.3 相关函数说明
workqueue*create_workqueue(*name) |
创建工作队列;返回一个工作队列;name为工作队列名字 |
destroy_workqueue(struct workqueue_struct *wq) |
销毁工作队列;wq为工作队列指针 |
queue_work(*wq,*work) |
调度一个指定的工作;wq工作队列指针;work工作指针 |
INIT_WORK(*work,callfunc) |
动态初始化工作;work为工作结构指针;callfunc为回调函数 |
schedule_work(*work) |
工作调度;work为工作指针 |
schedule_delayed_work(*work,delay) |
调度后延时执行;work工作指针;delay延时时间 |
29.4 工作队列实例
在驱动编写中,我们可以创建一个新的队列,也可以用内核已有的工作队列,这样我们就可以少去创建工作队列的代码,而直接用内核工作队列,这一般是满足我们的开发需要的。
实例1:使用内核工作队列,由内核定时器模拟中断产生调度。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/slab.h> //kmalloc头文件
#define I_DEVICE_NAME "iTimer"
static int major;
static struct timer_list tm;
struct work_struct *work1;/*工作队列*/
void iTimer_callback(unsigned long arg)
{
struct timeval tv;
char *strp = (char*)arg;
printk(KERN_EMERG "%s: %lu, %s\n", __func__, jiffies, strp);
schedule_work(work1);
mod_timer(&tm,jiffies+6*HZ); //每6s模拟触发一次中断调度
}
//工作队列处理函数
void work_CallBackfunc()
{
printk(KERN_EMERG "this is second part work\n");
}
static const struct file_operations stfops = {
.owner = THIS_MODULE,
};
static int __init iTest_Init(void)
{
/* 主设备号设置为0表示由系统自动分配主设备号 */
major = register_chrdev(0, I_DEVICE_NAME, &stfops);
/*Linux内核定时器初始化*/
init_timer(&tm);
tm.function= iTimer_callback;
tm.data = (unsigned long)"I am timer";
tm.expires = jiffies+1*HZ;
add_timer(&tm);
//创建工作队列
work1=kmalloc(sizeof(struct work_struct),GFP_KERNEL); //第二个参数是标志
INIT_WORK(work1,work_CallBackfunc);
return 0;
}
static void __exit iTest_Exit(void)
{
unregister_chrdev(major, I_DEVICE_NAME);
del_timer(&tm);
}
module_init(iTest_Init);
module_exit(iTest_Exit);
MODULE_LICENSE("GPL");
实例2:创建新工作队列及构建工作。
static struct workqueue_struct *miki_test_wq;//声明工作队列
static struct work_struct miki_test_work;;//声明工作
/*工作处理函数*/
static void miki_test_work_callback ()
{
//这里添加相应的逻辑,比如每隔5秒让闪关灯亮一次等
}
/*主函数*/
void mian()
{
//创建自己的工作队列
miki_test_wq = create_singlethread_workqueue("miki_test");
//初始化工作,实际上是让工作work绑定工作处理函数miki_test_work_callback
INIT_WORK(&miki_test_work, miki_test_work_callback);
//调度执行一个指定(miki_test_wq)中的任务miki_test_work
queue_work(miki_test_wq, &miki_test_work);
}