用例程解释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. C#/Entity Frame Core 使用Linq 进行分页 .Skip() .Take() 的使用方法

    一般使用格式为 int pagesize = 分页大小(每一页大小)int pageindex = 第几页(一般这个变量是随循环递增的) 使用方法.Skip(pagesize*pageindex).T ...

  2. Linux命令--权限管理

    chmod命令 Linux/Unix 的文件调用权限分为三级 : 文件拥有者.群组.其他.利用 chmod 可以藉以控制文件如何被他人所调用. 使用权限 : 所有使用者 语法 chmod [-cfvR ...

  3. codeforces 809C Find a car

    codeforces 809C Find a car 题意 有个\(1e9*1e9\)的矩阵,行 \(x\) 从上到下递增,列 \(y\) 从左到右递增.每个格子有一个正值.\((x, y)\) 的值 ...

  4. facebook页面种简单测试js调用flash开放的js接口的方法

    无意间折腾出来的,此方法很triky,但是很简单有效. 背景说明: facebook种内嵌的iframe无法直接访问. 解决方法: chrome浏览器为例 1.右键查看iframe源代码,此时进入if ...

  5. Python ,pickle

    @Python pickle模块学习   pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. ---------------------------------------- ...

  6. showDoc项目文档管理工具

    1:下载showdoc代码文件 https://github.com/star7th/showdoc https://www.showdoc.cc/help?page_id=14 官方帮助文档 2:安 ...

  7. 基于LNMP的小米电子商务网站平台

    项目参考:http://www.cnblogs.com/along21/p/7822228.html 基于LNMP的小米电子商务网站平台 1.环境 setenforce 0 #关闭selinux sy ...

  8. On Java 8中文版 英雄召集令

    这是该项目的GITHUB地址:https://github.com/LingCoder/OnJava8 广招天下英雄,为开源奉献!让我们一起来完成这本书的翻译吧! 如果您在阅读本书的过程中有发现不明白 ...

  9. 关于RFID电动车防盗、校园答题卡(超低功耗2.4G芯片SI24R2E)

          Si24R2E 是一颗工作在2.4GHz ISM 频段,专为低功耗有源RFID 应用场合设计,集成嵌入式发射基带的无线发射芯片.128 次可编程NVM 存储器以及自动发射模块.工作频率范围 ...

  10. linux挂在新硬盘

    login as: rootroot@192.168.109.128's password:Last login: Fri Mar 22 14:12:08 2019 from 192.168.109. ...