linux workqueue (workqueue) - very detailed and easy to understand

http://blog.csdn.net/liuxd3000/article/details/7700247

When dealing with kernel-related work, we often see workqueues. This article describes what is linux workqueue. This article is based on the 2.6.32 kernel, and the work queue at this time is not cmwq.

Why use workqueue?

In the kernel code , it is often desirable to defer part of the work to a future time for many reasons, e.g.

it is not appropriate to do a lot of (or time-consuming) work while holding a lock
. It is desirable to aggregate the work to gain batch performance ..calling
a function that may cause sleep makes it very inappropriate to perform a new schedule at this time.
...
there are many mechanisms provided in the kernel to provide delayed execution, the most used is the workqueue. .such

as the second half of the interrupt processing can be Delay part of the work in the interrupt context ; .Timer
can specify a delay to perform some work after a certain period of time;
.workqueue allows delayed execution in the context of the process ; .The
slow work mechanism that appeared briefly in the kernel (slow work mechanism);
.asynchronous function calls; .thread
pools of various private implementations;
...
term

workqueue: all work items (work that need to be performed) are queued on this queue.
worker thread: is a workqueue for executing The kernel thread of each work item in the workqueue, when there is no work item in the workqueue, the thread will become idle state.
single threaded(ST): one of the manifestations of worker thread, in the system-wide, only one worker thread serves the workqueue.
multi threaded(MT): one of the manifestations of worker thread, on each CPU on a multi-CPU system There is a worker thread serving the workqueue.
Use the steps


to create a workqueue (if using the kernel default workqueue, this step is skipped).
Create a work item work_struct.
Submit a work item to the workqueue.
Work item


data structure (slightly adjusted):


struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
    struct lockdep_map lockdep_map;
};
struct delayed_work {
    struct work_struct work;
    struct timer_list timer;
};
statically create work items:

DECLARE_WORK(n, f)
DECLARE_DELAYED_WORK(n, f)
dynamically Create a work item:

INIT_WORK(struct work_struct work, work_func_t func); 
PREPARE_WORK(struct work_struct work, work_func_t func); 
INIT_DELAYED_WORK(struct delayed_work work, work_func_t func); 
PREPARE_DELAYED_WORK(struct delayed_work work, work_func_t func); 
The default workqueue of the kernel can be seen from the

source code, the kernel defaults The global workqueue should be:

// Define
static struct workqueue_struct *keventd_wq __read_mostly;


// Initialize
...
keventd_wq = create_workqueue("events"); // MT worker thread mode.
...


// Confirm the corresponding number of kernel threads, Should be equal to the number of CPU cores
$ lscpu
Architecture: x86_64
CPU(s): 3
Thread(s) per core: 1
$ ps aux | grep "events"
root 9 0.0 0.0 0 0 ? S Feb09 1:15 [events/0]
root 10 0.0 0.0 0 0 ? S Feb09 0:59 [events/1]
root 11 0.0 0.0 0 0 ? S Feb09 0:59 [events/2 ]
A work item is added to keventd_wq by one of the following two functions:


int schedule_work(struct work_struct *work)
{
    return queue_work(keventd_wq, work);
}
int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
{
    return queue_delayed_work(keventd_wq, dwork, delay);
}
User-defined workqueue

to create workqueue:

create_singlethread_workqueue(name) // Corresponds to only one kernel thread
create_workqueue(name) // Corresponds to multiple kernel threads, same as above.
Submit work items to workqueue:

int queue_work(workqueue_t *queue, work_t *work); 
int queue_delayed_work(workqueue_t *queue, work_t *work, unsigned long delay); 
Cancel the pending work items in the workqueue and release the workqueue. Skip it here.

The advantages of the work queue are

easy to use .Execute in
the context of the process, so that it can sleep, be scheduled and preempted.
It is also very friendly to use in a multi-core environment.
example

#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue. h>

static struct workqueue_struct *queue = NULL;
static struct work_struct work;

static void work_handler(struct work_struct *data)
{
    printk(KERN_ALERT "work handler for work_item in queue helloworkqueue\n");
    // each work in workqueue is done The workqueue is then removed.
    // The following statement will cause a "crash", probably because the workqueue is taking up all the CPU time.
    // queue_work(queue, &work);
}

static int __init test_init(void)
{
    queue = create_singlethread_workqueue("helloworkqueue");
    if (!queue)
    {   
        goto err;
    }   
    INIT_WORK(&work, work_handler);
    queue_work(queue, &work);

    return 0;
err:
    return -1; 
}
static void __exit test_exit(void)
{
    destroy_workqueue(queue);
}

MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);
view rawworkqueue_example.cThis Gist brought to you by GitHub.
Makefile:

obj-m := wq.o
default:
    make -C /usr/src/linux-2.6.32.12-0.7 M=`pwd` modules


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325476258&siteId=291194637