One: Work queue concept
The work queue can be pushed back to a kernel thread to execute, the work queue runs in the context of the process, the work queue is running reschedule, or even the sleep kernel driver typically gives the lower half to the kernel default worker thread.
Two: Steps to use a work queue in a drive
1, declare a WORK_STRUCT structure
[CPP]View Plaincopy
- struct work_struct work;
2, dynamically create a work to point to, the handler function is Func
[CPP]View Plaincopy
- Init_work (struct work_struct *work,Void (*func) (void*),void*data)
- Example: Init_work (&work,android_work);
- static void Android_work (struct work_struct *data)
Note: the Android_work () function is called by a kernel thread and runs in the context of the process, but does not run access to the user space
3, on the job scheduling
The job scheduler is to give the work handler to the default events worker thread
[CPP]View Plaincopy
- Schedule_work (&work);
Three: Principles of the Task Force column
Work queue-related data structure is a struct workqueue_struct, the system default work queue name is: KEVENTD_WQ, the default worker thread is called: events/n, where n is the number of processors, each processor corresponds to a thread. For example, a single-processor system only events/0 such a thread. The dual-processor system will have one more EVENTS/1 thread. The creation of the default work queue Keventd_wq and worker thread events/n is implemented in file kernel/kernel/workqueue.c
Four: Create your own Work queue
[CPP]View Plaincopy
- struct workqueue_struct *create_workqueue (cost char* name)
Used to create a workqueue queue that creates a kernel thread for each CPU in the system. Input parameters
[CPP]View Plaincopy
- Create_singlethread_workqueue () Create only one task column
- int queue_work (struct workqueue_struct*wq,struct work_struct *work)
V: Supplement
The implementation of the work queue written on the book is to create a separate thread to perform the corresponding works. But the latest kernel implementations are not, and the interface of the original work queue is almost obsolete.
New API:
[CPP]View Plaincopy
- Alloc_workqueue (name, flags, max_active)
- Alloc_ordered_workqueue (const char *name, unsigned int flags)
- {
- Return Alloc_workqueue (name, Wq_unbound | flags, 1);
- }
When a task is submitted to a work queue, it does not run in the specified thread, and the system maintains a worker pool, each worker running in a separate thread, each CPU having a worker pool. When there is work to be done, it wakes up a worker, which reduces system resource usage (the original implementation is to create a thread each time a task queue is created, because each thread needs to have task_struct, PID and other resources, so that when the system in a number of Task Force column, The resource occupancy rate is very high). Because kernel space is a single address space shared by all processes, the user does not have to care about the process in which the work is being submitted by the different processes to the Task force, but in this case, if two jobs need to be synchronized (such as when accessing a shared resource), you have to think it over. When two jobs are submitted to the same work queue, they may be executed concurrently (running on separate CPUs), so that race is generated, and in order to solve this problem, the WQ_UNBOUND flag and max_acitve = 1 are introduced, and the two parameters indicate when a work is submitted to this task Force, This work will not be tied to a specific CPU (if the WQ_UNBOUND flag is not specified, the CPU on which the work is committed will be performed on that CPU), max_active indicates how many worker threads are bound to it in the background of the task queue, the default parameter is 0, Let the system specify the number of background threads.
[Linux kernel]linux interrupt the lower half--work queue