用例程解释create_singlethread_workqueue与create_workqueue的区别

系统版本:linux3.4

使用create_singlethread_workqueue创建工作队列即使对于多CPU系统,内核也只负责在一个cpu上创建一个worker_thread内核线程;而使用create_workqueue创建工作队列对于多CPU系统,内核将会在每个CPU上创建一个worker_thread内核线程,使得线程处理的事务能够并行化.

用代码解释前先说明一个知识点:
  printk任何时候,任何地方都能调用它,可以在中断上下文和进程上下文中被调用,可以在任何持有锁时被调用;可以在多处理器上同时被调用,而且调用者连锁都不必使用

==========================================================================================

例程1:使用create_workqueue创建工作队列

#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include <linux/workqueue.h>
#include <linux/delay.h> //工作以队列结构组织成工作队列(workqueue),其数据结构为workqueue_struct,
static struct workqueue_struct *test_wq = NULL; //把推后执行的任务叫做工作(work),描述它的数据结构为work_struct
static struct work_struct work; /*
*定义工作队列调用函数
*/
void work_func(struct work_struct *work){ while(){
printk(KERN_ERR "-----%s-----\n",__func__); //printk可以在多处理器上同时被调用
}
} static int __init test_init(void){ /*创建工作队列workqueue_struct,该函数会为cpu创建内核线程*/
test_wq = create_workqueue("test_wq"); /*初始化工作work_struct,指定工作函数*/
INIT_WORK(&work,work_func); /*将工作加入到工作队列中,最终唤醒内核线程*/
queue_work(test_wq, &work); while(){
mdelay();
printk(KERN_ERR "-----%s-----\n",__func__);
} return ;
} static void __exit test_exit(void){ } module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liujin725@outlook.com");

运行结果:没有打印任何信息,系统直接卡死,卡死原因是因为所有的cpu都被printk占用,系统无法调用其他的进程

=============================================================================

例程2:使用create_singlethread_workqueue创建工作队列

#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include <linux/workqueue.h>
#include <linux/delay.h> //工作以队列结构组织成工作队列(workqueue),其数据结构为workqueue_struct,
static struct workqueue_struct *test_wq = NULL; //把推后执行的任务叫做工作(work),描述它的数据结构为work_struct
static struct work_struct work; /*
*定义工作队列调用函数
*/
void work_func(struct work_struct *work){ while(){
printk(KERN_ERR "-----%s-----\n",__func__); //printk可以在多处理器上同时被调用
}
} static int __init test_init(void){ /*创建工作队列workqueue_struct,该函数会为cpu创建内核线程*/
test_wq = create_singlethread_workqueue("test_wq"); /*初始化工作work_struct,指定工作函数*/
INIT_WORK(&work,work_func); /*将工作加入到工作队列中,最终唤醒内核线程*/
queue_work(test_wq, &work); while(){
mdelay();
printk(KERN_ERR "-----%s-----\n",__func__);
} return ;
} static void __exit test_exit(void){ } module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liujin725@outlook.com");

运行结果:
<3>[ 124.050211] -----work_func-----   //work_func有打印
<3>[ 124.244364] -----work_func-----
<3>[ 124.341765] -----work_func-----
<3>[ 124.537000] -----work_func-----
<3>[ 124.630770] -----work_func-----
<3>[ 124.801644] -----test_init-----    //test_init有打印
<3>[ 124.825084] -----work_func-----



一直打印log

==========================================================================
总结:
使用create_workqueue创建的工作队列在工作执行函数work_func中循环调用printk会导致系统卡死,是因为create_workqueue创建工作队列时在每个cpu上都创建了worker_thread内核线程,worker_thread线程处理的事务能够并行化,导致所有的cpu都被printk函数所占用,系统无法调用其他的进程,所以系统出现卡死并且无任何log信息打印

而使用create_singlethread_workqueue创建的工作队列只在一个cpu上创建worker_thread内核线程,即使该cpu一直被printk占用也还有其他的cpu可以继续调用其他的进程,所以能够一直打印log

附:
推荐一篇工作队列讲的挺不错的博客:http://bgutech.blog.163.com/blog/static/18261124320116181119889/

用例程解释create_singlethread_workqueue与create_workqueue的区别的更多相关文章

  1. 用通俗的例子解释OAuth和OpenID的区别【原】

    什么是OAuth(Wiki) 什么是OpenID(Wiki) 详细的定义可以看wiki,下面举个例子说说我的理解 现在很多网站都可以用第三方的账号登陆,比如,现在我要登录淘宝买东西,而如果我没有淘宝的 ...

  2. 三种角度解释href/src/link/import区别

    网上查到的几种不同但比较容易理解的解释 解释一: href是Hypertext Reference的缩写,表示超文本引用.用来建立当前元素和文档之间的链接.常用的有:link.a.例如: <li ...

  3. 事件冒泡和事件捕获以及解释target和currenttarget的区别

    冒泡和捕获的区别是冒泡事件是先触发子元素事件,再触发父元素事件,这个是冒泡.捕获是先触发父元素事件,再触发子元素事件.简单的来说,冒泡的顺序是由内到外,捕获的顺序是由外到内 举例:<!DOCTY ...

  4. Python工程文件中的名词解释---Module与Package的区别

    当我们在已有的Python工程文件中创建新的内容是,通常会有两种类型文件供你选择---Module和Package,对于初学者来说会搞不清楚这两种文件直接的关系.这里就来解释一下这两者之间的关系. M ...

  5. 小例子解释wait与notify的区别

    系统慢可能有很多种原因,硬件资源不足,语句不优化,结构设计不合理,缺少必要的运维方式.所有的这些问题都可以在阻塞与等待中看出端倪,发现并解决问题. 首先是下载开发工具,磨刀不误砍材工.点此下载 这是一 ...

  6. 请解释final finally finalize的区别

    final  关键字 ,可以定义不能被继承的父类.定义不能被重写的方法,常量 finally   关键字, 异常处理的统一出口 不管是否有异常都执行 finalize   方法(protected   ...

  7. WPF中ControlTemplate和DataTemplate的区别

    下面代码很好的解释了它们之间的区别: <Window x:Class="WPFTestMe.Window12" xmlns="http://schemas.micr ...

  8. 有关于break,continue,return的区别和代码分析

    今天,用代码和结果直接解释break,continue,return的区别 1.break代码 public static void breakTest() { //break的讲解 for(int ...

  9. C#经典面试题 C# 中 Struct 与 Class 的区别,以及两者的适用场合

    在一家公司面试时,第一个问题就是问到这个 转载 文章 http://www.cnblogs.com/waitrabbit/archive/2008/05/18/1202064.html  来解释此问题 ...

随机推荐

  1. Linux Kernel 4.11首个候选版本开放下载

    Linus Torvalds宣布了即将到来的Linux Kernel 4.11内核分支的首个候选(RC)版本,用户可下载.编译并在自己的GNU/Linux发行版本中进行测试.Linus Torvald ...

  2. visio 修改画布大小

    按住Ctrl,鼠标移到画布边缘,拖拉即可.

  3. Hibernate 一次查询分多次返回 避免内存溢出

    public void grpcGpioDevice(StreamObserver<NI_GetAllDeviceListResponse> responseObserver, Map&l ...

  4. Java.util 包(Date 类、Calendar类、Random类)

    java.util 包提供了一些实用的方法和数据结构. Date 类 Date 类表示日期和时间,里面封装了操作日期和时间的方法.Date 类经常用来获取系统当前时间. 构造方法: 构造方法 说明 D ...

  5. API接口数据自检

    这个周末的娱乐,通用模块,让后端自检,严格客户端按照文档的要求来,妈妈再也不担心我加班了,对某些团队来说,可能根本用不着,本是想到就尝试一把而已. 哎,傻X的客户端程序员,时间都去推辞扯淡打扮啦,好好 ...

  6. Mysql不带条件更新报错

    执行命令SET SQL_SAFE_UPDATES = 0;修改下数据库模式即可: 恢复安全模式:SET SQL_SAFE_UPDATES = 1;

  7. 3109. [CQOI2013]新数独【DFS】

    Description Input 输入一共15行,包含一个新数独的实例.第奇数行包含左右方向的符号(<和>),第偶数行包含上下方向的符号(^和v).   Output 输出包含9行,每行 ...

  8. 【[HNOI2015]亚瑟王】

    神仙题,抄题解 用\(tp_i\)表示\(i\)这个技能在\(r\)轮中被使用过的概率 于是最后的答案就是\(\sum_{i=1}^nd_i*tp_i\) 首先\(tp_1=1-(1-p_1)^r\) ...

  9. hbase性能调优(1)

    hbase性能调优 标签: hbase 性能调优 | 发表时间:2014-05-17 15:10 | 作者:无尘道长 分享到: 出处:http://www.iteye.com 一.服务端调优 1.参数 ...

  10. Autoware 安装流程

    1. 前言 最近一个项目采用Autoware的无人驾驶系统,在安装工控机的过程中,踩了不少坑,留下记录,造福后人. 相关的下载在我的百度网盘,大家自行下载.链接: https://pan.baidu. ...