linux驱动学习之工作队列使用
2012-12-12 14:29
393 查看
工作队列是一种将工作推后执行的形式,交由一个内核线程去执行在进程上下文执行,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。工作队列子系统提供了一个默认的工作者线程来处理这些工作。默认的工作者线程叫做events/n,这里n是处理器的编号,每个处理器对应一个线程,也可以自己创建工作者线程。
1.工作的定义
2.使用内核提供的共享列队
测试例子
在线程函数内设置了测试点如下
主要函数
主要测试代码
测试结果
1.工作的定义
typedef void (*work_func_t)(struct work_struct *work); 定义中初始化处理函数 DECLARE_WORK(n, f); #define DECLARE_WORK(n, f) struct work_struct n = __WORK_INITIALIZER(n, f) #define __WORK_INITIALIZER(n, f) { \ .data = WORK_DATA_INIT(0), \ .entry = { &(n).entry, &(n).entry }, \ .func = (f) \ } 先定义中后初始化处理函数 struct work_struct INIT_WORK(struct work_struct *work, func_t); #define INIT_WORK(_work, _func) \ do { \ __INIT_WORK((_work), (_func), 0); \ } while (在使用带delay的函数或宏时使用DECLARE_DELAYED_WORK定义和INIT_DELAYED_WORK初始化。
2.使用内核提供的共享列队
对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。 int schedule_work(struct work_struct *work); 确保没有工作队列入口在系统中任何地方运行。 void flush_scheduled_work(void); 延时执行一个任务 int schedule_delayed_work(struct delayed_struct *work, unsigned long delay); 从一个工作队列中去除入口; int cancel_delayed_work(struct delayed_struct *work);
测试例子
void myfunc(struct work_struct*ws); DECLARE_WORK(mywork,myfunc); //定义 void myfunc(struct work_struct*ws) { printk(KERN_ALERT "myfunc current->pid %d\n",current->pid); ssleep(1); printk(KERN_ALERT "myfunc current->pid %d\n",current->pid); ssleep(1); printk(KERN_ALERT "myfunc current->pid %d\n",current->pid); ssleep(1); } 在加载模块时调用 schedule_work(&mywork); printk(KERN_ALERT "main current->pid %d\n" ,current->pid);测试结果
输出的pid main current->pid 2883 myfunc current->pid 4 myfunc current->pid 4 myfunc current->pid 4 [root@fontlose module]# ps PID USER VSZ STAT COMMAND 1 root 2108 S init 2 root 0 SW [ksoftirqd/0] 3 root 0 SW [watchdog/0] 4 root 0 SW< [events/0]myfunc运行在pid为4的进程中,查看pid为4的进程为events/0,使用内核提供的共享列队,列队是保持顺序执行的,做完一个工作才做下一个,如果一个工作内有耗时大的处理如阻塞等待信号或锁,那么后面的工作都不会执行。如果你不喜欢排队或不好意思让别人等太久,那么可以创建自己的工作者线程,所有工作可以加入自己创建的工作列队,列队中的工作运行在创建的工作者线程中。
3.使用自定义列队
创建工作列队使用3个宏 成功后返回workqueue_struct *指针,并创建了工作者线程。三个宏主要区别在后面两个参数singlethread和freezeable,singlethread为0时会为每个cpu上创建一个工作者线程,为1时只在当前运行的cpu上创建一个工作者线程。freezeable会影响内核线程结构体thread_info的PF_NOFREEZE标记if (!cwq->freezeable) current->flags |= PF_NOFREEZE; set_user_nice(current, -5);
在线程函数内设置了测试点如下
if (cwq->freezeable) try_to_freeze();如果设置了PF_NOFREEZE这个flag,那么系统挂起时候这个进程不会被挂起。
主要函数
#define create_workqueue(name) __create_workqueue((name), 0, 0) //多处理器时会为每个cpu创建一个工作者线程 #define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1) //只创建一个工作者线程,系统挂起是线程也挂起 #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) //只创建一个工作者线程,系统挂起是线程线程不挂起 以上三个宏调用__create_workqueue函数定义 extern struct workqueue_struct *__create_workqueue(const char *name,int singlethread, int freezeable); 释放创建的工作列队资源 void destroy_workqueue(struct workqueue_struct *wq) 延时调用指定工作列队的工作 queue_delayed_work(struct workqueue_struct *wq,struct delay_struct *work, unsigned long delay) 取消指定工作列队的延时工作 cancel_delayed_work(struct delay_struct *work) 将工作加入工作列队进行调度 queue_work(struct workqueue_struct *wq, struct work_struct *work) 等待列队中的任务全部执行完毕。 void flush_workqueue(struct workqueue_struct *wq);
主要测试代码
void myfunc(struct work_struct*ws); struct workqueue_struct *wqueue; DECLARE_WORK(mywork,myfunc); void myfunc(struct work_struct*ws) { printk(KERN_ALERT "myfunc 1 current->pid %d\n",current->pid); ssleep(1); printk(KERN_ALERT "myfunc 2 current->pid %d\n",current->pid); ssleep(1); printk(KERN_ALERT "myfunc 3 current->pid %d\n",current->pid); ssleep(1); } 在模块加载是执行 wqueue=create_workqueue("myqueue"); queue_work(wqueue,&mywork); printk(KERN_ALERT "main current->pid %d\n" ,current->pid);
测试结果
main current->pid 1010 myfunc 1 current->pid 1016 myfunc 2 current->pid 1016 myfunc 3 current->pid 1016 ps .... 1016 root 0 SW< [myqueue/0]可见函数运行在pid为1016的进程中,ps查看进程名为myqueue/0.
相关文章推荐
- linux驱动学习之工作队列机制
- linux驱动开发之输入子系统编程(一)使用工作队列实现中断下半部
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】中断服务下半部之工作队列详解
- Linux 驱动中工作队列的使用
- linux work queue工作队列小结与使用
- linux驱动学习之内核定时器使用
- android底层驱动学习之工作队列work_queue相关参数
- Linux工作队列的使用
- 如何使用Linux工作队列workqueue
- Linux work queue工作队列小结与使用
- Android深度探索:HAL与驱动开发学习笔记--工作队列
- linux驱动增加work工作队列和获取唤醒锁操作
- Linux工作队列的使用
- linux设备驱动--内核等待队列知识点---结合中断使用
- linux驱动编程--工作队列浅析
- 学习笔记:Linux驱动开发git基本使用流程
- 基于mini6410的linux驱动学习总结(三 使用驱动程序)
- linux驱动学习之旗标的使用
- 完全使用Linux学习和工作
- Kobuki学习之一:Linux驱动安装(不使用ROS)