2、表示工作的数据结构
工作用<linux/workqueue.h>中定义的work_struct结构表示:
struct work_struct{ unsigned long pending; struct list_head entry; void (*func) (void *); void *data; void *wq_data; struct timer_list timer; }; |
这些结构被连接成链表。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作被执行完毕,它就将相应的work_struct对象从链表上移去。当链表上不再有对象的时候,它就会继续休眠。
3、创建推后的工作
要使用工作队列,首先要做的是创建一些需要推后完成的工作。可以通过DECLARE_WORK在编译时静态地建该结构:
DECLARE_WORK(name, void (*func) (void *), void *data); |
这样就会静态地创建一个名为name,待执行函数为func,参数为data的work_struct结构。
同样,也可以在运行时通过指针创建一个工作:
INIT_WORK(struct work_struct *work, woid(*func) (void *), void *data); |
这会动态地初始化一个由work指向的工作。
4、工作队列中待执行的函数
工作队列待执行的函数原型是:
void work_handler(void *data) |
这个函数会由一个工作者线程执行,因此,函数会运行在进程上下文中。默认情况下,允许响应中断,并且不持有任何锁。如果需要,函数可以睡眠。需要注意的是,尽管该函数运行在进程上下文中,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射。通常在系统调用发生时,内核会代表用户空间的进程运行,此时它才能访问用户空间,也只有在此时它才会映射用户空间的内存。
5、对工作进行调度
现在工作已经被创建,我们可以调度它了。想要把给定工作的待处理函数提交给缺省的events工作线程,只需调用
schedule_work(&work); |
work马上就会被调度,一旦其所在的处理器上的工作者线程被唤醒,它就会被执行。
有时候并不希望工作马上就被执行,而是希望它经过一段延迟以后再执行。在这种情况下,可以调度它在指定的时间执行:
schedule_delayed_work(&work, delay); |
这时,&work指向的work_struct直到delay指定的时钟节拍用完以后才会执行。