一、延迟工作介绍
延迟工作是一种将工作的执行延迟到稍后时间点进行处理的技术。通常情况下,当某个任务需要花费较长时间,不需要立即执行或需要按时执行时,延迟工作就会派上用场。
延迟工作的基本思想是将任务放入一个队列中,然后由后台的工作进程会任务调度程序来处理队列中的任务。任务可以在指定的延迟时间后执行,也可以根据优先级,任务类型或者其他条件进行排序和处理。
延迟工作在许多应用场景中都非常有用,尤其是在需要处理大量任务,提供系统性能和可靠性的情况下。以下是一些常用的应用场景
1 延迟工作常用于处理那些需要花费较长时间的任务,比如发送电子邮件,处理图像等。通过将这些任务放入队列中并延迟执行,可以避免阻塞应用程序的主线程,提高系统的响应速度。
2 延迟工作可以用来执行定时任务,比如定时备份数据库,通过将任务设置为在未来的某个时间点执行,提高系统的可靠性和效率。
例如按键消抖除了使用定时器方式进行消抖,也可以使用延迟工作来消抖。
在 Linux 内核中,使用 struct delayed_work 来描述延迟工作,定义在include/linux/workqueue.h 当中,原型定义如下所示:
struct delayed_work{
struct work_struct work;// 延迟工作的基本工作结构
struct timer_list timer;// 定时器,用于延迟执行工作
};
struct delayed_work 结构体包含了两个成员:
1 work:这是一个 struct work_struct 类型的成员,用于表示延迟工作的基本工作结构。structwork_struct 是表示工作的常见数据结构,用于定义要执行的工作内容。
2 timer:这是一个 struct timer_list 类型的成员,用于管理延迟工作的定时器。struct timer_list是 Linux 内核中的定时器结构,用于设置延迟时间和触发工作执行的时机。
使用 struct delayed_work 结构体,可以将需要执行的工作封装成一个延迟工作,并使用定时器来控制工作的延迟执行。通过设置定时器的延迟时间,可以指定工作在一定时间后执行。
二、延迟工作相关接口函数
2.1、初始化延迟工作函数
静态定义并初始化延迟工作使用宏 DECLARE_DELAYED_WORK,函数原型如下所示:
#define DECLARE_DELAYED_WORK(n,f) struct delayed_work n = { .work = __WORK_INITIALIZER(n.work, (f)) }
使用宏定义后,可以将上述代码简化为#define DECLARE_DELAYED_WORK(n,f),n代表延迟工作的变量名,f 是延迟工作的处理函数。
动态定义并初始化延迟工作使用宏 INIT_DELAYED_WORK,函数原型如下所示:
#define INIT_DELAYED_WORK(_work, _func) \
do { \
INIT_WORK(&(_work)->work, (_func)); \
(_work)->timer = TIMER_INITIALIZER((_work)->timer, 0, 0); \
} while (0)
使用宏定义后,可以将上述代码简化为#define INIT_DELAYED_WORK(_work, _func),n代表延迟工作的变量名,f 是延迟工作的处理函数。
2.2、调度延迟工作函数
如果是在共享工作队列上调度延迟工作,使用以下函数:
static inline bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay )
该函数是一个内联函数,用于在给定的延迟时间后调度延迟工作执行。函数参数 dwork:是指向延迟工作的指针,即要被调度的延迟工作。delay:表示延迟的时间长度,以内核时钟节拍数 jiffies 为单位。
如果是在自定义工作队列上调度延迟工作,使用以下函数:
static inline bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay)
该函数是一个内联函数,用于将延迟工作加入工作队列后在指定的延迟时间后执行。函数参数 wq 是指向工作队列结构的指针,即要将延迟工作加入的目标工作队列。dwork:指向延迟工作的指针,也就是要被加入工作队列的延迟工作。delay: 表示延迟的时间长度,以内核时钟节拍数 jiffies 为单位。
2.3、取消调度延迟工作函数
如果要取消调度函数,使用以下函数:
extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
该函数是一个外部声明的函数,用于取消延迟工作并等待其完成。dwork 参数是指向延迟工作的指针,也就是要被取消的延迟工作。函数如果返回 true,说明成功取消延迟工作并等待其完成。函数如果返回 false,说明无法取消延迟工作或等待其完成。
三、代码示例
3.1、驱动层程序
#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 delayed_work 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_delayed_work(test_workqueue, &test_workqueue_work, 3 * HZ);
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 = create_workqueue("test_workqueue");
// 初始化延迟工作项
INIT_DELAYED_WORK(&test_workqueue_work, test_work);
return 0;
}
static void interrupt_irq_exit(void)
{
free_irq(irq, NULL); // 释放中断
cancel_delayed_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);
3.2、linux中断下文工作队列之延迟工作使用API要点
// 初始化延迟工作项
INIT_DELAYED_WORK(&test_workqueue_work, test_work);
// 提交延迟工作项到自定义工作队列
queue_delayed_work(test_workqueue, &test_workqueue_work, 3 * HZ);
cancel_delayed_work_sync(&test_workqueue_work); // 取消延迟工作项