用例程解释create_singlethread_workqueue与create_workqueue的区别
用例程解释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的区别的更多相关文章
- 用通俗的例子解释OAuth和OpenID的区别【原】
什么是OAuth(Wiki) 什么是OpenID(Wiki) 详细的定义可以看wiki,下面举个例子说说我的理解 现在很多网站都可以用第三方的账号登陆,比如,现在我要登录淘宝买东西,而如果我没有淘宝的 ...
- 三种角度解释href/src/link/import区别
网上查到的几种不同但比较容易理解的解释 解释一: href是Hypertext Reference的缩写,表示超文本引用.用来建立当前元素和文档之间的链接.常用的有:link.a.例如: <li ...
- 事件冒泡和事件捕获以及解释target和currenttarget的区别
冒泡和捕获的区别是冒泡事件是先触发子元素事件,再触发父元素事件,这个是冒泡.捕获是先触发父元素事件,再触发子元素事件.简单的来说,冒泡的顺序是由内到外,捕获的顺序是由外到内 举例:<!DOCTY ...
- Python工程文件中的名词解释---Module与Package的区别
当我们在已有的Python工程文件中创建新的内容是,通常会有两种类型文件供你选择---Module和Package,对于初学者来说会搞不清楚这两种文件直接的关系.这里就来解释一下这两者之间的关系. M ...
- 小例子解释wait与notify的区别
系统慢可能有很多种原因,硬件资源不足,语句不优化,结构设计不合理,缺少必要的运维方式.所有的这些问题都可以在阻塞与等待中看出端倪,发现并解决问题. 首先是下载开发工具,磨刀不误砍材工.点此下载 这是一 ...
- 请解释final finally finalize的区别
final 关键字 ,可以定义不能被继承的父类.定义不能被重写的方法,常量 finally 关键字, 异常处理的统一出口 不管是否有异常都执行 finalize 方法(protected ...
- WPF中ControlTemplate和DataTemplate的区别
下面代码很好的解释了它们之间的区别: <Window x:Class="WPFTestMe.Window12" xmlns="http://schemas.micr ...
- 有关于break,continue,return的区别和代码分析
今天,用代码和结果直接解释break,continue,return的区别 1.break代码 public static void breakTest() { //break的讲解 for(int ...
- C#经典面试题 C# 中 Struct 与 Class 的区别,以及两者的适用场合
在一家公司面试时,第一个问题就是问到这个 转载 文章 http://www.cnblogs.com/waitrabbit/archive/2008/05/18/1202064.html 来解释此问题 ...
随机推荐
- Navicat for mysql 导出导入的问题
问题现象 1:使用navicat 导出5.6.20版本数据库,然后导入到5.7.19mysql出现错误:
- kotlin lateinit
声明变量: private var a: String? = "" 或者:private lateinit var a: String // 使用前先初始化
- Shell脚本例子集合
# vi xx.sh 退出并保存 # chmod +x xx.sh # ./xx.sh -2. 调试脚本的方法 # bash -x xx.sh 就可以调试了 . -1. 配置 secureCRT 的设 ...
- python 网络编程 -- Tcp协议
Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 客户端 大多数连接都是可靠 ...
- Discuz的一处越权操作,强制回复无权限帖子
合购vip 等教程论坛 都用的是Discuz 看操作步骤: 随便找一处vip教程 接下来 我们审查元素 找到这段代码 然后修改 <a href="http://xxx.xxx.xx ...
- IDEA 常用插件收藏
1.maven helper 查看maven依赖,解决jar包冲突. 2.Alibaba Java Coding Guidelines 代码风格遵循阿里java规范. 3.Lombok 简化实体中的 ...
- springMVC <mvc:interceptors>拦截器的使用
首先在springMVC.xml配置如下代码 <!-- 拦截器 --> <mvc:interceptors> <bean class="com.base.Acc ...
- Java类修饰符的使用与作用以及常见问题
首先明确,类是放在文件里的,在文件里面的不同位置就有不同的作用,就是不同类型的类. 1, 顶级类or外部类:包括两种,一个文件中与文件名同名称的类我们称作顶级类(也是外部类),如果在一个文件中的一个类 ...
- Window窗口布局 --- DecorView浅析
开发中,通常都是在onCreate()中调用setContentView(R.layout.custom_layout)来实现想要的页面布局,我们知道,页面都是依附在窗口之上的,而DecorView即 ...
- Asp.Net Core + Ocelot 网关搭建:负载均衡的配置
前言 上一篇中简单做了一个网关Demo.本篇中也记录一下负载均衡的配置实现. 演示 首先开三个服务,端口分别为 60001,60003,60005,然后分别启动三个服务.接下来在ApiGate ...