#include <linux/delay.h>
#include <linux/rtc.h>
static struct delayed_work mdwq;
static struct workqueue_struct *mwq;
static void delay_work_func(struct work_struct *work) {
int i;
struct timex txc;
struct rtc_time tm;
for (i = 0; i < 5; i++) {
do_gettimeofday(&(txc.time));
rtc_time_to_tm(txc.time.tv_sec,&tm);
printk("[%d-%02d-%02d %02d:%02d:%02d]%s:i=%d\n",
tm.tm_year+1900,tm.tm_mon+1, tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,
__FUNCTION__,i);
msleep(1000);
}
}
static int __init delay_work_init(void) {
int ret;
int i;
mwq = create_workqueue("my workqueue");
if (!mwq) {
printk(KERN_ERR "Create workqueue failed!\n");
return 1;
}
struct timex txc;
struct rtc_time tm;
do_gettimeofday(&(txc.time));
rtc_time_to_tm(txc.time.tv_sec,&tm);
printk("[%d-%02d-%02d %02d:%02d:%02d][%s:Create workqueue successful!]\n",
tm.tm_year+1900,tm.tm_mon+1, tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,
__FUNCTION__);
INIT_DELAYED_WORK(&mdwq, delay_work_func);
ret = queue_delayed_work(mwq, &mdwq, msecs_to_jiffies(3000));
printk(KERN_INFO "%s queue_delayed_work result=[%d]\n", __FUNCTION__, ret);
return 0;
}
static void __exit delay_work_exit(void) {
int ret;
ret = cancel_delayed_work(&mdwq);
flush_workqueue(mwq);
destroy_workqueue(mwq);
printk(KERN_INFO "Exit! ret=%d\n", ret);
}
module_init(delay_work_init);
module_exit(delay_work_exit);
MODULE_LICENSE("GPL");
有5秒钟延时的运行结果
$ insmod queuework_driver.ko
[2020-07-20 16:31:38][delay_work_init:Create workqueue successful!]
delay_work_init queue_delayed_work result=[1]
[2020-07-20 16:31:41]delay_work_func:i=0
[2020-07-20 16:31:42]delay_work_func:i=1
[2020-07-20 16:31:43]delay_work_func:i=2
[2020-07-20 16:31:44]delay_work_func:i=3
[2020-07-20 16:31:45]delay_work_func:i=4
$ ps
117 root 0:00 [my workqueue/0]
$ rmmod queuework_driver
Exit! ret=0
执行逻辑
create_workqueue
创建工作队列 workqueue_struct,该函数会为cpu创建内核线程
INIT_DELAYED_WORK
初始化延迟的工作 work_struct,指定工作函数
queue_delayed_work
将初始化后的延迟的工作 加入到工作队列中,在第三个参数指定的时间周期后去执行
如果不使用延时 则是分别替换掉三个函数
// INIT_DELAYED_WORK, queue_delayed_work, cancel_delayed_work
INIT_WORK(&mdwq.work, delay_work_func);
ret = queue_work(mwq, &mdwq);
ret = cancel_work_sync(&mdwq);
修改后,为不延时的运行结果
$ insmod queuework_driver.ko
[2020-07-20 16:49:31][delay_work_init:Create workqueue successful!]
[2020-07-20 16:49:31]delay_work_func:i=0
delay_work_init queue_delayed_work result=[1]
[2020-07-20 16:49:32]delay_work_func:i=1
[2020-07-20 16:49:33]delay_work_func:i=2
[2020-07-20 16:49:34]delay_work_func:i=3
[2020-07-20 16:49:35]delay_work_func:i=4
$ rmmod queuework_driver
Exit! ret=0
可以看出时间上是没有间隙的。
这里需要预先了解有使用ps查看当前进程可以看到 [events/0]
[events/0] 属于单核的处理器提供了一个死循环的缺省的工作者线程
用巡视的方式处理队列中的任务
可以通过 INIT_DELAYED_WORK 在这个任务队列中加入一个任务
并且调用 queue_delayed_work 来通知更新了队列以便巡视的时候多个一个任务需要执行
在 queue_delayed_work 之后,工作 func 就会被 [events/0] 执行到。
其中两个重要结构体
struct delayed_work mdwq; // 指向需要执行的函数
struct workqueue_struct *mwq; // 工作队列
补充
create_workqueue
创建一个任务。
Linux 3.10 之后的版本用 alloc_workqueue 代替 create_workqueue
但是当前我的测试环境为 Linux 2.6 所以仍然使用 create_workqueue
以上为使用了自己的工作队列,即自定义队列
在许多情况下,设备驱动程序不需要有自己的工作队列。如果我们只是偶尔需要向队列中提交任务,
则一种更简单、更有效的办法是使用内核提供的共享的默认工作队列。
使用 schedule_work 可以把工作提交到共享工作队列中,由内核默认提供的工作队列[events/0]执行。
static int __init delay_work_init(void) {
int ret;
int i;
struct timex txc;
struct rtc_time tm;
do_gettimeofday(&(txc.time));
rtc_time_to_tm(txc.time.tv_sec,&tm);
printk("[%d-%02d-%02d %02d:%02d:%02d][%s(pid=%d):Create workqueue successful!]\n",
tm.tm_year+1900,tm.tm_mon+1, tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,
__FUNCTION__, current->pid);
INIT_WORK(&mdwq.work, delay_work_func);
ret = schedule_work(&mdwq.work);
printk(KERN_INFO "%s queue_delayed_work result=[%d]\n", __FUNCTION__, ret);
return 0;
}
static void __exit delay_work_exit(void) {
int ret;
ret = cancel_work_sync(&mdwq);
//flush_workqueue(mwq);
//destroy_workqueue(mwq);
printk(KERN_INFO "Exit! ret=%d\n", ret);
}
输出相关的线程的ID可以看到
$ insmod queuework_driver.ko
[2020-07-20 16:49:31][delay_work_init(pid=100):Create workqueue successful!]
[2020-07-20 16:49:31]delay_work_func(pid=4):i=0
delay_work_init queue_delayed_work result=[1]
[2020-07-20 16:49:32]delay_work_func(pid=4):i=1
[2020-07-20 16:49:33]delay_work_func(pid=4):i=2
[2020-07-20 16:49:34]delay_work_func(pid=4):i=3
[2020-07-20 16:49:35]delay_work_func(pid=4):i=4
$ ps
4 root 0:00 [events/0]
$ rmmod queuework_driver
Exit! ret=0
可以看出执行的线程是 ID为4的[events/0],所以表示使用 schedule_work 把工作提交到
内核默认提供的工作队列[events/0]执行了。
需要使用工作队列时,可以考虑内核提供的下面两种接口
schedule_work/schedule_delayed_work
create_workqueue/queue_work/queue_delayed_work
schedule_work | 把任务提交到内核默认提供的工作队列[events/0]中执行 |
schedule_delayed_work | 把任务提交到内核默认提供的工作队列[events/0]中,(延时一定的时间)执行 |
queue_work | 把任务提交到自定义创建的队列[my workqueue/0]中执行 |
queue_delayed_work | 把任务提交到自定义创建的队列[my workqueue/0]中,(延时一定的时间)执行 |
INIT_WORK | 把需要执行的函数初始化(封装)为一个工作队列中的任务 |
使用 ps 命令可以查看两者在内核中属于不同线程 4 root 0:00 [events/0] 以及 117 root 0:00 [my workqueue/0]今天的文章自定义队列queue_work和内核共享列队schedule_work分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23908.html