介绍:

      一组并发线程运行在同一进程上下文中,每一个线程都有自己独立的线程上下文,包括线程ID、栈、栈指针、程序计数器、条件码和通用目的寄存器。每个线程和其他线程一起共享进程上下文的其他部分,包括整个用户虚拟地址空间(由代码段、读/写数据、堆以及所有共享库的代码和数据区组成)。线程也共享打开的文件集合。当存在共享资源的时候,对资源的访问需要同步。这时候使用线程编写程序的时候,需要编写具有线程安全性属性的函数。一个函数,当且仅当被多个并发线程反复调用时,能够一直产生正确的结果,才能够被称为线程安全的,否则我们称其为非线程安全的。


可重入的特点:

  1. 由于可重入函数多次调用不会出错,所以不必担心数据被破坏;

  2. 可重入函数在任何时候都可以被中断,一段时间后又可以运行,相应的数据不会丢失;

  3. 可重入函数只使用局部变量,即保存在CPU寄存器或者堆栈中,使用全局变量要加以保护;


不可重入的特点:

  1. 使用malloc/free函数,malloc函数是用全局链表来管理堆栈的;

  2. 调用标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构;

  3. 可重入体内使用了静态数据结构;

常见的不可重入函数有:

    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