引子:单线程程序只有一个控制流。不需要考虑静态或全局变量被同时访问或并发访问,但是多线程程序必须考虑并发访问一个资源。为了保证资源的完整性,为多线程程序写的代码必须是可重入的和线程安全的。
1.0 定义:
线程安全的(Thread-Safe):如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的。线程安全函数解决多个线程调用函数时访问共享资源的冲突问题。
可重入(Reentrant):函数可以由多于一个线程并发使用,而不必担心数据发生改变,可重入函数可以在任意时刻被中断,稍后再继续运行,而结果总是唯一的。可重入性解决函数运行结果的确定性和可重复性。
volatile 避免编译器对变量做冗余装载和存储删去的优化,即告诉编译器每次操作被volatile修饰的变量都直接从内存读取或者写回内存,而不是只操作寄存器里的备份.(全局共享的数据一般建议使用volatile关键字保护)
2.0 两者之间的关系:
- 一个函数对于多个线程是可重入的,则这个函数是线程安全的。
- 一个函数是线程安全的,但并不一定是可重入的。
- 可重入性要强于线程安全性。
两者的侧重点不一样:
- 线程安全强调的是函数并发或者异步使用时不会相互干扰,如果函数使用共享资源(静态变量/全局变量),则需要加锁保证互斥访问
- 可重入强调的是函数并发或者异步使用时结果总是唯一的,函数不能使用共享资源。
线程安全函数,满足以下两点之一:
- 不使用静态或全局数据等共享资源
- 使用了共享资源,但加锁保护
可重入的函数需要做到如下三点
- 不在函数内部使用静态或全局数据
- 不返回静态或全局数据,所有数据都由函数的调用者提供。
- 不调用不可重入函数
使用volatile的情况有
- 内存映射硬件
- 中断服务程序/信号处理程序中会访问到的全局变量
- 多进程应用中的共享内存和多线程应用中被几个线程共享的变量
命题: 全局A赋值给C
赋值过程: 赋值过程 先A赋值给B ,再B赋值给C
主进程:先A赋值给B B = A ; 在这产生中断
中断: 调用到A ,并A = D,退出中断。
主进程: 再B赋值给C, B = C。