中断处理程序不能使用printf的本质
vxworks 中断处理程序之所以不用printf,本质在于printf是将信息输出到标准输出设备(STDOUT)中, 整个标准输出设备是一个全局变量,由于有semTake操作,那么就会发生阻塞,vxworks属于硬实时操作系统,不能在规定的时间内完成操作即会死机或复位。所以vxworks不用printf的原因在于阻塞。 网上说printf 因为引用全局变量stdout,所以是不可重入的。这个稍微解释一下。如果用到了全局变量,但是用信号量保护,是线程安全的,但是不可重入的(会导致死锁,譬如一个任务或中断处理程序调用了printf,被另一个高优先级中断打断,那么就会形成死锁而导致系统复位)。
所以这里的阻塞和不可重入都是因为对共享变量的保护而采用互斥锁引起的,而这里的阻塞是不可重入的一个真子集。(例如:可能有些函数对静态或全局变量没有锁保护,因此是非线程安全,也是非可重入的,此时并没有阻塞在静态或全局变量上,所以不可重入的概念要大。)。因此printf不能用在中断处理程序中的根本原因在于使用了全局变量后采用了锁机制,而锁机制会导致阻塞,阻塞是不可重入的真子集。 所以网上说printf因为不可重入,也会说得过去的(但不可重入还有其他非阻塞的场景)。更准确的说法是因为阻塞在全局变量STDOUT上)。关于可重入和线程安全的区别,下文会有详细解释:
线程安全函数
• 概念:
线程安全的概念比较直观。一般说来,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。
• 确保线程安全:
要确保函数线程安全,主要需要考虑的是线程之间的共享变量。属于同一进程的不同线程会共享进程内存空间中的全局区和堆,而私有的线程空间则主要包括栈和寄 存器。因此,对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量、局部静态变量、分配于堆的变量都是共享的。在对这些共享变量进行访 问时,如果要保证线程安全,则必须通过加锁的方式。
• 线程不安全的后果:
线程不安全可能导致的后果是显而易见的——共享变量的值由于不同线程的访问,可能发生不可预料的变化,进而导致程序的错误,甚至崩溃。
可重入函数
• 概念:
可重入的概念基本没有比较正式的完整解释,多数的文档都只是说明什么样的情况才能保证函数可重入,但没有完整定义。按照Wiki上的说法,“A computer program or routine is described as reentrant if it can be safely executed concurrently; that is, the routine can be re-entered while it is already running.”根据笔者的经验,所谓“重入”,常见的情况是,程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理
函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入。此时如果foo()能够正确的运行,而且处理完成后,之前暂停的foo()也能够正确运行,则说明它是可重入的。
• 确保可重入:
要确保函数可重入,需满足以下几个条件:
1、不在函数内部使用静态或全局数据
2、不返回静态或全局数据,所有数据都由函数的调用者提供。
3、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。
4、不调用不可重入函数。
• 不可重入的后果:
不可重入的后果主要体现在象信号处理函数这样需要重入的情况中。如果信号处理函数中使用了不可重入的函数,则可能导致程序的错误甚至崩溃。
可重入与线程安全
可重入与线程安全并不等同。一般说来,可重入的函数一定是线程安全的,但反过来不一定成立。
- 如果一个函数中用到了全局或静态变量,那么它不是线程安全的,也不是可重入的;
- 如果我们对它加以改进,在访问全局或静态变量时使用互斥量或信号量等方式加锁,则可以使它变成线程安全的,但此时它仍然是不可重入的,因为通常加锁方式是针对不同线程的访问,而对同一线程可能出现问题;这里举例说明:假设函数func() 在执行过程中需要访问某个共享资源,因此为了实现线程安全,在使用该资源前加锁,在不需要资源解锁。
假设该函数在某次执行过程中,在已经获得资源锁之后,有异步信号发生,程序的执行流转交给对应的信号处理函数;再假设在该信号处理函数中也需要调用函数 func() ,那么func() 在这次执行中仍会在访问共享资源前试图获得资源锁,然而我们知道前一个func() 实例已然获得该锁,因此信号处理函数阻塞。另一方面,信号处理函数结束前被信号中断的线程是无法恢复执行的,当然也没有释放资源的机会,这样就出现了线程和信号处理函数之间的死锁局面。
因此,func() 尽管通过加锁的方式能保证线程安全,但是由于函数体对共享资源的访问,因此是非可重入。如果将函数中的全局或静态变量去掉,改成函数参数等其他形式,则有可能使函数变成既线程安全,又可重入。比如:strtok函数是既不可重入的,也不是线程安全的;加锁的strtok不是可重入的,但线程安全;而strtok_r既是可重入的,也是线程安全的。
中断处理程序不能使用printf的本质的更多相关文章
- Linux从头学07:中断那么重要,它的本质到底是什么?
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...
- 驱动:中断【2】中断处理程序、中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)
中断处理程序.中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)http://blog.csdn.net/samantha_sun/article/details/6790492 1,中 ...
- linux内核--中断处理程序
一个设备的中断处理程序是它设备驱动程序的一部分--设备驱动程序是用于对设备进行管理的内核代码.中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断 ...
- linux内核分析笔记----中断和中断处理程序【转】
转自:http://www.cnblogs.com/hanyan225/archive/2011/07/17/2108609.html 中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因 ...
- linux内核分析笔记----中断和中断处理程序
中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因为在操作系统中,中断是必须要讲的.. 那么什么叫中断呢, 中断还是打断,这样一说你就不明白了.唉,中断还真是有点像打断.我们知道linu ...
- 13.linux中断处理程序
linux中断处理程序 一.中断处理流程 在linux内核代码中进入entry-armv.S目录: linux统一的入口:__irq svc. 进入了统一的入口之后,程序跳到irq_handler标号 ...
- 中断——中断处理程序的进入与退出 (基于3.16-rc4)
上一篇博文我们分析了中断描述符表的中断门初始化过程,并且在interrupt数组中初始化过程中,可以看到每个中断处理程序都会跳入common_interrupt中.下面我们分析下common_inte ...
- 【译】x86程序员手册33-9.6中断任务和中断处理程序
9.6 Interrupt Tasks and Interrupt Procedures 中断任务和中断处理程序 Just as a CALL instruction can call either ...
- (转) 中断处理程序&中断服务例程
关于中断处理程序和中断服务例程ISR的区别及联系,之前一直搞混,今天抽时间将两者关系弄弄清楚.ok,下面进入主题. 首先中断处理程序(Interrupt Handler) ...
随机推荐
- jQuery应用操作之---复选框
1.示例1: <form> 你最爱好的运动是? <input type="checkbox" id="CheckedAll"/>全选&l ...
- 在CentOS7上实现NFS共享
一.介绍 NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,功能是让客户端通过网络访问不同主机上磁盘里的数据,主要用在类Unix系统上实现文件共享 ...
- Oracle打印日历功能
Oracle用SQL打印日历 1.1 打印当月日历 , D, NULL)) SUN, , D, NULL)) MON, , D, NULL)) TUE, , D, NULL)) WED, , D, ...
- HEOI2016 题解
HEOI2016 题解 Q:为什么要在sdoi前做去年的heoi题 A:我省选药丸 http://cogs.pro/cogs/problem/index.php?key=heoi2016 D1T1 树 ...
- 使用DateTimeOffset 对xml中的日期时间格式时区进行处理
在日常使用中难免会与XML打交道,其中一个常用的格式就是日期了. 交互的时候通常有下面2种方式 DECLARE @Doc XML=' <R> <T>2018-02-22+08: ...
- 讲解mybaits的标签语法
前言:mybatis作为一个持久层的java框架,高度封装了jdbc原始代码,它拥有比Hiberante更便捷.更直接的sql语法和sql灵活配置的特性,比如简单的一个自动映射对象就大大减少了我们的代 ...
- Java基础点滴
1. 关于interface的定义 [修饰符] interface 接口名 [extends 父接口名列表]{ [public] [static] [final] 常量;[public] [abstr ...
- tpframe框架之slide模块的使用
最新版git:https://gitee.com/37duman/tpframe 下载插件 点击下载slide插件 安装插件 把下载下来的插件解压后放置在addon文件夹 登录后台,点击插件管理 点击 ...
- Python自动化--语言基础4--模块、文件读写、异常
模块1.什么是模块?可以理解为一个py文件其实就是一个模块.比如xiami.py就是一个模块,想引入使用就在代码里写import xiami即可2.模块首先从当前目录查询,如果没有再按path顺序逐一 ...
- Linux 小记 — 网络管理
前言 前段时间需要配置一台私网 ECS 联外网,阿里云比较推荐的方案是创建一个 Nat 网关并绑定 EIP, 以此来统一所有 ECS 的网络出口.由于我已经拥有一台外网 ECS(不想多掏钱,且我自己的 ...