Linux内核工作队列使用

VERSION:5.4.24

参考:
include/linux/workqueue.h

实际需要

定时器、下半部 tasklet,它们都是在中断上下文中执行,它们无法休眠。当要处理更复杂的事情时,往往更耗时。这些更耗时的工作放在定时器或是下半部中,会使得系统很卡;并且循环等待某件事情完成,这样太浪费 CPU 资源了。

如果使用线程来处理这些耗时的工作,那就可以解决系统卡顿的问题:因为线程可以休眠。

在内核中,我们并不需要自己去创建线程,可以使用“工作队列”(workqueue)。内核初始化工作队列时,就为它创建了内核线程。以后要使用“工作队列”,只需要把“工作”放入“工作队列中”,对应的内核线程就会取出“工作”,执行里面的函数。

重要的结构体,函数

  • 核心 work_struct 结构体

    /*
     * 只关注 func: 线程执行函数
     */
    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

    /*
     * 只关注 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;
    };
    
  • 初始化工作队列

    • 方法一

      /*
       * @_work: work_struct 指针
       * @_func: 要执行的函数
       */
      #define INIT_WORK(_work, _func)						\
      	__INIT_WORK((_work), (_func), 0)
      
    • 方法二

      /*
       * @_work: delayed_work 指针
       * @_func: 要执行的函数
       */
      #define INIT_DELAYED_WORK(_work, _func)					\
      	__INIT_DELAYED_WORK(_work, _func, 0)
      
  • 把工作任务放入全局工作队列

    • 方法一

      /**
        * schedule_work - 将工作任务放入全局工作队列
        * @work:要完成的工作
        *
        * 如果@work 已经在内核全局工作队列中,则返回 false,否则返回 true。
        *
        * 如果作业尚未排队,则将其放入内核全局工作队列中,否则将其留在内核全局工作队列中的相同位置。
        */
      static inline bool schedule_work(struct work_struct *work)
      {
      	return queue_work(system_wq, work);
      }
      
    • 方法二

      /**
        * schedule_delayed_work - 延迟后将工作任务放入全局工作队列
        * @dwork:有待完成的工作
        * @delay: 等待的 jiffies 数量或立即执行的 0
        *
        * 等待给定时间后,这会将作业放入内核全局工作队列中。
        */
      static inline bool schedule_delayed_work(struct delayed_work *dwork,
      					 unsigned long delay)
      {
      	return queue_delayed_work(system_wq, dwork, delay);
      }
      

内核工作队列使用示例一

  • 第一步:构造结构体

    /* 结构体 */
    struct work_struct my_work;
    
    /* 任务函数 */
    void work_func (struct work_struct *pwork)
    {
    	/* user code */
    }
    
  • 第二步:初始化工作队列

    /* 
     * 在合适的位置添加这一句代码来初始化定时器 
     * 一般在驱动的 probe,open函数里使用  
     */
    INIT_WORK(&my_work, work_func);
    
  • 第三步:把工作任务放入全局工作队列

    /* 在合适的位置添加这一句代码来启动任务 */
    schedule_work(&my_work);
    

内核工作队列使用示例二

  • 第一步:构造结构体

    /* 结构体 */
    struct delayed_work my_delayed_work;
    /* 任务函数 */
    void work_func (struct work_struct *pwork)
    {	
    	/* user code */
    }
    
  • 第二步:初始化工作队列

     /*
      * 在合适的位置添加这一句代码来初始化定时器
      * 一般在驱动的 probe,open函数里使用
      */
      INIT_DELAYED_WORK(&my_delayed_work, work_func);
    
  • 第三步:把工作任务放入全局工作队列

    /* 在合适的位置添加这一句代码来启动任务 */
    schedule_delayed_work(&my_delayed_work, msecs_to_jiffies(500)); /* 500ms 后执行 */
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值