用例程解释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. js实现查找字符串出现最多的字符和次数

    代码如下: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=" ...

  2. Linux下tomcat端口、自启问题

    一.防火墙开放8080端口命令: 以下命令只针对 CentOs 7 以上版本,CentOS升级到7之后,使用firewalld代 替了原来的iptables: 启动: # systemctl star ...

  3. Linux系统下安装Redis和Redis集群配置

    Linux系统下安装Redis和Redis集群配置 一. 下载.安装.配置环境: 1.1.>官网下载地址: https://redis.io/download (本人下载的是3.2.8版本:re ...

  4. August 11th 2017 Week 32nd Friday

    I can't give you the world, but I can give you my world. 我不能给你全世界,但是我的世界我可以全部给你. Maybe I can't give ...

  5. ZT A2DP协议笔记

    A2DP协议笔记 (2013-07-30 10:07:54) 转载▼ 标签: a2dp bluetooth src sink 分类: Bluetooth 1.概述     A2DP(Advanced ...

  6. PDF转WORD工具推荐:迅捷PDF转换器6.8版

    迅捷PDF转换器是一款功能强大的pdf转换成word转换器软件.它不仅支持pdf转换成word,word转pdf,还可以实现excel,ppt,jpg与pdf文件的一键式转换.有了它,你可以很轻松转换 ...

  7. ipconfig命令一览

    前文用到了ipconfig /displaydns和ipconfig /flushdns,加上之前经常ipconfig查ip,今天看了一下别的命令,用的不多,仅作备忘~~ 命令行窗口中输入ipconf ...

  8. js字符串和数组

    sustr  substring  slice的联系与区别 str.substr(2,5) //从索引2开始截取5个字符,原有字符串str不变 str.substring(2,5) //从索引2开始截 ...

  9. Java基础知识强化之集合框架笔记78:ConcurrentHashMap之 ConcurrentHashMap、Hashtable、HashMap、TreeMap区别

    1. Hashtable: (1)是一个包含单向链的二维数组,table数组中是Entry<K,V>存储,entry对象: (2)放入的value不能为空: (3)线程安全的,所有方法均用 ...

  10. ZooKeeper学习之路 (四)ZooKeeper开发环境eclipse配置

    一.eclipse中配置zookeeper开发环境 1)将zookeeper eclipse plugin中的6个jar包放到eclipse安装目录下的plugins文件中,重启eclipse (2) ...