Linux工作队列workqueue实现分析

工作队列是Linux内核中用于调度内核线程执行任务的接口,每个任务有自己的工作队列(workqueue_struct)。每种任务可能对应一个CPU上的工作者线程,由worker_thread函数创建。工作队列包含一个工作链表(worklist),当有任务加入时,工作者线程被唤醒执行任务。工作结构(work_struct)定义了任务,由func指针指向实际执行函数。create_workqueue创建工作队列,并为每个CPU分配结构体,启动工作者线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
参考资料:《Linux内核设计与实现》第3版 LKD3e、linux-2.6.27

        工作队列子系统是一个用于调用创建内核线程的接口,通过它创建的线程负责执行由内核其它部分排到队列里的任务。这些内核线程称为工作者线程。工作队列子系统提供了一个缺省的工作都线程来处理工作。一般使用缺省线程即可,但当处理密集型和性能要求严格的任务时,创建拥有自己的工作者线程比较好。(引至LKD3e)

        这个接口就是create_workqueue(),它返回一个struct workqueue_struct 结构指针。
        /*
         * The externally visible workqueue abstraction is an array of
         * per-CPU workqueues:
         */
        struct workqueue_struct {
            struct cpu_workqueue_struct *cpu_wq;
            struct list_head list;
            const char *name;
            int singlethread;
            int freezeable;     /* Freeze threads during suspend */
        #ifdef CONFIG_LOCKDEP
            struct lockdep_map lockdep_map;
        #endif
        };
        上面注释:外部可见的工作队列抽象是由per-CPU的工作队列组成的数组,这个数组为结构体 cpu_workqueue_struct 。所以每种任务,它有一个自己的工作队列(struct workqueue_struct ),这个工作队列如果需要的话会为每个CPU创建对应的工作者线程。也就是说每个CPU,每个工作者线程对应一个cpu_workqueue_struct。

        /*
         * The per-CPU workqueue (if single thread, we always use the first
         * possible cpu).
         */
        struct cpu_workqueue_struct {
        
            spinlock_t lock;
        
            struct list_head worklist;
            wait_queue_head_t more_work;
            struct work_struct *current_work;
        
            struct workqueue_struct *wq;
            struct task_struct *thread;
        
            int run_depth;      /* Detect run_workqueue() recursion depth */
        } ____cacheline_aligned;
        刚才说了,每种任务,它都有一个自己的工作队列,这种任务的抽象就是为每个CPU创建一个处理这种任务的工作者线程(当然这是需要的情况下,如果不需要则会使用默认的工作者线程events/n,n为CPU编号),那么这个wq就是关联到自己的工作队列workqueue_struct。所有的工作者线程都是用普通的内核线程实现的,由worker_thread()函数完成。
当为一个CPU创建完一个线程后,这个线程执行死循环开始休眠,当有操作插入到队列时,线程被唤醒并执行。(LKD3e)

        对应的具体工作由work_struct结构:
        struct work_struct {
            atomic_long_t data;
            struct list_head entry;
            work_func_t func;
        };
        由list_head可知,它是个双向链表,每个结点为一个work_struct结构类型。每个CPU上的每种类型的队列都对应这样一个链表。当一个工作线程被唤醒时,它会执行这个链表上的所有工作;工作执行完毕后就从链表上先移除相应的work_struct;当链表上不再有对象时就继续休眠。
        总得来说就是每种任务(可以理解成为处理不同数据结构),有一个workqueue_struct。每个CPU有多个工作者线程,
        每个线程处理相应的任务。处理过程最终调用的是func。至于func是怎么赋值的可参考下面代码实现。

        下面再看下linux内核具体实现,看一下create_workqueue是怎样创建工作者线程的,代码有很多内核同步机制,暂时不关注。
        #define create_workqueue(name) __create_workqueue((name), 0, 0)
        #define __create_workqueue(name, singlethread, freezeable)  \//singlethread为0
        ({                              \
            static struct lock_class_key __key;         \
         &nbs
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值