linux驱动35:工作队列
工作队列类似于tasklet,都允许内核代码请求某个函数在将来的时间被调用。
区别:
tasklet运行在软件中断上下文,tasklet代码必须是原子的。工作队列函数在一个特殊内核进程的上下文中运行,可以休眠。
tasklet始终运行在被初始化提交的同一处理器上,这是工作队列的默认方式。
内核代码可以请求工作队列函数的执行延迟给定的时间间隔。
tasklet会在很短的时间段内很快执行,并以原子模式执行,而工作队列函数可具有更长的延迟并且不必原子化。
头文件:
<linux/workqueue.h>
接口:
创建一个工作队列
struct workqueue_struct *create_workqueue(const char *name);//内核会在系统中的每个处理器上为该工作队列创建专用的线程
struct workqueue_struct *create_singlethread_workqueue(const char *name);//创建单个工作线程
struct workqueue_struct结构初始化
INIT_WORK(struct workqueue_struct *, void (func) (struct work_struct *));//首次构造结构
工作提交到工作队列
int queue_work(struct workqueue_struct *queue, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay);
在将来的某个时间,工作函数会被调用,运行在工作线程的上下文,如果有必要,可以休眠。该函数不能访问用户空间。
取消某个挂起的工作队列入口项
int cancel_delayed_work(struct work_struct *work);//入口项执行前被取消返回非零值
刷新工作队列
nt cancel_delayed_work(struct workqueue_struct *queue);//任何在该调用之前被提交的工作函数都不会在系统任何地方运行
释放工作队列
void destroy_workqueue(struct workqueue_struct *queue);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/workqueue.h>
typedef struct
{
char data[32];
struct work_struct test_work;
}MY_WORK_S;
static struct timeval lastTime;
static struct workqueue_struct *pMyWorkQueue;
static MY_WORK_S myWork;
static int cnt = 0;
void my_work_func(struct work_struct *work)
{
struct timeval curTime;
MY_WORK_S *p = container_of(work, MY_WORK_S, test_work);
printk("%s:%s\n", __func__, p->data);
do_gettimeofday(&curTime);
printk("interval: %ld s, %ld us\n",
curTime.tv_sec - lastTime.tv_sec, curTime.tv_usec - lastTime.tv_usec);
if (cnt <= 5)
{
queue_work(pMyWorkQueue, &myWork.test_work);
cnt++;
}
}
static int __init hello_init(void)
{
printk("hello_init. \n");
pMyWorkQueue = create_singlethread_workqueue("myworkqueue");
strcpy(myWork.data, "hello");
INIT_WORK(&myWork.test_work, my_work_func);
queue_work(pMyWorkQueue, &myWork.test_work);
do_gettimeofday(&lastTime);
return 0;
}
static void __exit hello_exit(void)
{
printk("hello_exit. \n");
destroy_workqueue(pMyWorkQueue);
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);