相信大家在面试的时候都有被问到过这个问题。如何保证线程安全?
线程安全,即在多线程的环境下,可访问的全局变量和堆数据随随时都可能被其他的线程改变。因此多线程程序在并发时数据的一致性变得非常重要。
原子操作
即代码经过编译后变成汇编文件,每行代码都翻译成汇编直连,我们把一行代码对应一条汇编指令的操作,称之为原子操作。因为无论如何,单条指令的执行是不会被打断的。
锁
当我们需要保证一个复杂的数据结构更改时,原子操作就会力不从心了。这里就需要使用更加通用的手段了:锁。
为了避免多个线程同时读写一个数据而产生不可预料的后果,我们需要将各个线程对同一个数据的访问同步,所谓同步,即是指在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。
锁有很多种类型,用于使用不同的场景。
如互斥锁,自旋锁,读写锁,临界区,条件变量等
函数的可重入性
一个函数被重入,表示这个函数没有执行完成,由于外部因素或者内部调用,有一次执行该函数。
一个函数被冲入只有两种情况:
- 多个线程同时执行这个函数
- 函数递归
一个函数要成为可重入的,必须具有以下几个特点:
1. 不适用任何静态或者全局的非const变量
2. 不返回任何静态或全局的非const变量的指针
3. 仅依赖调用方提供的参数
4. 不依赖任何单个资源的锁
5. 不调用任何不可重入的函数
过度优化
编译器为了提高速率将一个变量缓存到寄存器中,而不将变量的值写回内存中。使用volatile来修饰该变量,可以阻止该行为。
编译器有可能会调整volatile变量的指令顺序。使用barrier指令来阻止换顺序。