可重入函数与线程安全
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可重入函数与线程安全相关的知识,希望对你有一定的参考价值。
介绍: 一组并发线程运行在同一进程上下文中,每一个线程都有自己独立的线程上下文,包括线程ID、栈、栈指针、程序计数器、条件码和通用目的寄存器。每个线程和其他线程一起共享进程上下文的其他部分,包括整个用户虚拟地址空间(由代码段、读/写数据、堆以及所有共享库的代码和数据区组成)。线程也共享打开的文件集合。当存在共享资源的时候,对资源的访问需要同步。这时候使用线程编写程序的时候,需要编写具有线程安全性属性的函数。一个函数,当且仅当被多个并发线程反复调用时,能够一直产生正确的结果,才能够被称为线程安全的,否则我们称其为非线程安全的。
可重入的特点:
由于可重入函数多次调用不会出错,所以不必担心数据被破坏;
可重入函数在任何时候都可以被中断,一段时间后又可以运行,相应的数据不会丢失;
可重入函数只使用局部变量,即保存在CPU寄存器或者堆栈中,使用全局变量要加以保护;
不可重入的特点:
使用malloc/free函数,malloc函数是用全局链表来管理堆栈的;
调用标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构;
可重入体内使用了静态数据结构;
常见的不可重入函数有:
printf----引用了全局变量stdout
malloc---全局内存分配表
free------全局内存分配表
线程安全与可重入:
可重入的定义源自于单线程环境。在单线程环境中,一段代码在执行中可能会被硬件中断,并转而调用中断服务程序(ISR)。在这次调用中断处理函数之前,有可能中断处理函数已经在执行。因此,任何中断处理函数都应该是可重入的。
线程安全的概念则是源自于多线程环境。起源不一样,那么他们之间也没有什么必然的关系。
面试题:
中断是嵌入式系统中重要的组成部分。新的关键字_interrupt。下面的代码就是用_interrupt关键字去定义了一个中断服务子程序(ISR),然后评论下面的代码;
__interrupt double compute_area (double radius) { double area = PI * radius * radius; printf("\nArea = %f", area); return area; }
代码错误:
1、ISR不能返回一个值。
2、ISR不能传递参数。
3、在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额外的寄存器入栈,有些处理器/编译器你就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4、printf()经常有重入和性能上的问题。
那么在这里就该有一个原则:
1、不要使用static变量和全局变量,坚持只用局部变量
2、如必须使用全局变量,利用互斥信号量来保护全局变量
3、获取得知哪些系统调用是可重入的,在多任务处理程序中都使用安全的系统调用
4、不调用其他任何不可重入的函数
5、谨慎使用malloc/free
以上是关于可重入函数与线程安全的主要内容,如果未能解决你的问题,请参考以下文章