Example of delayed work queue under linux platform

 http://blog.chinaunix.net/uid-25445243-id-4174402.html    

The work queue is a mechanism in the Linux kernel that delays the execution of operations. Because they are executed in the user context through the daemon, the time the function can sleep has nothing to do with the kernel. During the development of kernel version 2.5, a work queue was designed to replace the previous keventd mechanism.

        This mechanism is different from BH or Tasklets in that the work queue delegates the deferred work to a kernel thread for execution, so the advantage of the work queue is that it allows rescheduling or even sleep.

        Each work queue has one more array, the number of data elements is the same as the number of core processor cores, and each data element lists the tasks that will be postponed.

        For each work queue, the kernel creates a new kernel daemon thread, and deferred tasks use the waiting queue mechanism described in the context to execute in the morning and afternoon of the daemon.

First define a few terms used in the work queue in the kernel to facilitate the description later.

  • workqueues: All work items are arranged in this queue (work that needs to be executed), so they are called workqueues.
  • worker thread: A worker thread is a kernel thread used to execute each work item in the work queue. When there is no work item in the work queue, the thread will become idle.
  • single threaded(ST): One of the manifestations of worker threads, in the system scope, only one worker thread serves the work queue
  • multi threaded (MT): One of the manifestations of worker threads. On a multi-CPU system, each CPU has a worker thread to serve the work queue

How to use the work queue? Follow the steps below:

One. Declare a work queue

staticstruct workqueue_struct *test_wq;

two. Declare a deferred job description example

static struct delayed_work test_dwq;

three. Declare and implement a work queue delay processing function

voiddelay_func(struct work_struct *work);

voiddelay_func(struct work_struct *work)

{

    printk(KERN_INFO "My name isdelay_func!\n");

}

four. Initialize a work queue

test_wq = create_workqueue("test_wq");

Fives. Task initialization

INIT_DELAYED_WORK(&test_dwq,delay_func);

six. Submit work items to the work queue

queue_delayed_work(test_wq, &test_dwq, delay);

Seven. Cancel work items in the work queue

int cancel_delayed_work(test_wq);

       If this work item is cancelled before it starts execution, the return value is non-zero. The kernel guarantees that the execution of a given work item will not be executed after calling cancel_delay_work successfully. If cancel_delay_work returns 0, the work item may already be running on a different processor and may still be executed after cancel_delayed_work is called. To be absolutely sure that the work function does not run anywhere after cancel_delayed_work returns 0, you must follow this call followed by flush_workqueue. After flush_workqueue returns. Any work function submitted before the call will not run anywhere in the system.

Eight. Refresh the work queue

flush_workqueue(test_wq);

 

nine. Work queue destruction

destroy_workqueue(test_wq);

 

The main functions and structures involved

One. Function queue_delayed_work()

The function queue_delayed_work() is used to submit a delayed_work instance to the work queue to ensure that at least a period of time (in jiffies) specified by delay will pass before the execution is delayed.

This function first creates a timer by the kernel, the timer will time out within the delayed jiffies.

two. Example of deferred job description

structdelayed_work {

       struct work_struct work; /* Will be added to a work queue by queue_work or queue_work_delayed as an instance*/

       struct timer_list timer; /* delay time*/

};

three. alloc_workqueue function

struct workqueue_struct *alloc_workqueue(char *name, unsigned intflags, int max_active);

name: the name of the work queue, unlike the name of the kernel thread that actually serves the work queue before 2.6.36.

Flag:  Specify the attributes of the work queue. The flags that can be set are as follows:

  • WQ_NON_REENTRANT: By default, the work queue just ensures that it is not reentrant on the same CPU, that is, work items cannot be executed concurrently by multiple worker threads on the same CPU, but concurrent execution on multiple CPUs is allowed. However, this flag indicates that it is also non-reentrant on multiple CPUs. Work items will be queued in a non-reentrant work queue and ensure that at most one system-wide worker thread is executed.
  • WQ_UNBOUND: The work item is put into an unqualified work queue served by a specific gcwq, and the client worker thread is not limited to a specific CPU. In this way, the unqualified worker queue is like a simple execution context without concurrent management. The unqualified gcwq tries to execute work items as quickly as possible.
  • WQ_FREEZEABLE: can freeze wq to participate in the suspension operation of the system. The work items of the work queue will be suspended, unless awakened, otherwise no new work items will be executed.
  • WQ_MEM_RECLAIM: All work queues may be used on the memory recovery path. Using this flag ensures that there is at least one execution context regardless of any memory pressure.
  • WQ_HIGHPRI: High-priority work items will be rehearsed at the head of the queue, and the concurrency level will not be considered during execution; in other words, as long as resources are available, high-priority work items will be executed as quickly as possible. High priority work items are executed in the order of submission.

· WQ_CPU_INTENSIVE: CPU-intensive work items do not contribute to the concurrency level, in other words, runnable CPU-intensive work items will not block other work items. This is very useful for limited work items, because it expects more CPU clock cycles, so the scheduling of their execution is given to the system scheduler.

·         WQ_DRAINING:internal: workqueue is draining

·         WQ_RESCUER :internal: workqueue has rescuer

·         WQ_MAX_ACTIVE: I like 512, better ideas?

·         WQ_MAX_UNBOUND_PER_CPU: 4 * #cpus for unbound wq

· WQ_DFL_ACTIVE: equal to WQ_MAX_ACTIVE / 2,

max_active: Determines the maximum work item that wq can execute on per-CPU. For example, setting max_active to 16 means that up to 16 work items on a work queue can be executed simultaneously on the per-CPU. In current practice, for all limited work queues, the maximum value of max_active is 512, and when set to 0, it means 256; and for unqualified work queues, the maximum value is: MAX[512, 4 * num_possible_cpus() ], Unless there is a special reason for current limiting or other reasons, generally set to 0.

Instance

Guess you like

Origin blog.csdn.net/qq_26690505/article/details/90256490