工作队列是一种将工作推后执行的机制。
工作队列可以把工作推后,交由一个内核线程去执行,它是中断下半部分实现的一种形式,
而且它总是会在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。
最重要的就是工作队列允许重新调度甚至是睡眠。
工作的结构体声明
定义并初始化一个工作
定义并初始化一个延迟的工作
不定义仅初始化一个工作
不定义仅初始化一个延迟的工作
创建一个工作队列
动态创建的工作队列的指针;最后让该线程进行起来。
该函数将工作[work]加入到全局的工作队列[keventd_wq]中。
如果成功返回0,否则返回非0;
该函数将延迟delay长的时间后再把工作[work]加入到全局的工作队列[keventd_wq]中。
@dwork: 将要加入的工作
@delay: 延迟的时间,如果为0表示不延迟,立即运行
总结:
工作队列的用法:
1> 定义并初始化一个工作,可以用以下两个方法:
a) DECLARE_WORK(n, f)
3> 如果需要自定义一个工作者线程的话,那么:
a) 调用下面的函数创建一个工作者线程,创建一个工作队列
工作队列可以把工作推后,交由一个内核线程去执行,它是中断下半部分实现的一种形式,
而且它总是会在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。
最重要的就是工作队列允许重新调度甚至是睡眠。
工作的结构体声明
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
#define WORK_DATA_INIT() ATOMIC_LONG_INIT(0)
struct delayed_work {
struct work_struct work;
struct timer_list timer;
};
定义并初始化一个工作
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
#define __WORK_INITIALIZER(n, f) { \
.data = WORK_DATA_INIT(), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
}
定义并初始化一个延迟的工作
#define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
#define __DELAYED_WORK_INITIALIZER(n, f) { \
.work = __WORK_INITIALIZER((n).work, (f)), \
.timer = TIMER_INITIALIZER(NULL, 0, 0), \
}
不定义仅初始化一个工作
#define INIT_WORK(_work, _func) \
do { \
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
不定义仅初始化一个延迟的工作
#define INIT_DELAYED_WORK(_work, _func) \
do { \
INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \
} while (0)
/*
* initialize a work item's function pointer
*/
#define PREPARE_WORK(_work, _func) \
do { \
(_work)->func = (_func); \
} while (0)
#define PREPARE_DELAYED_WORK(_work, _func) \
PREPARE_WORK(&(_work)->work, (_func))
工作队列的结构体
struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq;
struct list_head list;
const char *name;
int singlethread;
int freezeable; /* Freeze threads during suspend */
int rt;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
/*
* 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;
} ____cacheline_aligned;
创建一个工作队列
#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
该函数会创建一个内核线程,该线程的名称就是传递的参数name;另外还会返回一个
动态创建的工作队列的指针;最后让该线程进行起来。
/**
* schedule_work - put work task in global workqueue
* @work: job to be done
*
* Returns zero if @work was already on the kernel-global workqueue and
* non-zero otherwise.
*
* This puts a job in the kernel-global workqueue if it was not already
* queued and leaves it in the same position on the kernel-global
* workqueue otherwise.
* 这将把一个工作加入到内核全局变量工作队列中,如果没有加入成功,那么将在
* 相同的地方leaves it.
*/
static struct workqueue_struct *keventd_wq;
int schedule_work(struct work_struct *work)
{
return queue_work(keventd_wq, work);
}
说明:
该函数将工作[work]加入到全局的工作队列[keventd_wq]中。
如果成功返回0,否则返回非0;
/**
* schedule_delayed_work - put work task in global workqueue after delay
* @dwork: job to be done
* @delay: number of jiffies to wait or 0 for immediate execution
*
* After waiting for a given time this puts a job in the kernel-global
* workqueue.
*/
int schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
return queue_delayed_work(keventd_wq, dwork, delay);
}
说明:
该函数将延迟delay长的时间后再把工作[work]加入到全局的工作队列[keventd_wq]中。
@dwork: 将要加入的工作
@delay: 延迟的时间,如果为0表示不延迟,立即运行
总结:
工作队列的用法:
1> 定义并初始化一个工作,可以用以下两个方法:
a) DECLARE_WORK(n, f)
b) INIT_WORK(_work, _func)
2> 如果用内核初始化好的工作者线程的话,那么只需要调用下面这个函数:
schedule_work(struct work_struct *work);
e.g. schedule_work(&zwmy_work);
3> 如果需要自定义一个工作者线程的话,那么:
a) 调用下面的函数创建一个工作者线程,创建一个工作队列
create_workqueue(name)
e.g. struct workqueue_struct * zwmy_wq;
zwmy_wq = create_workqueue(&zwmy_work);
b) 调用下面的函数将工作加入到工作队列中queue_work(struct workqueue_struct *wq, struct work_struct *work);
e.g. queue_work(zwmy_wq, &zwmy_work);