Linux 线程安全与线程同步
一、线程安全
1、概念
通过理解重入与线程安全的关系来理解线程安全。
线程安全即多个线程并发同一段代码时,不会出现不同的结果。
重入即同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入。一个函数在重入的情况下运行结果不会出现任何问题,这样的函数称为可重入函数,否则就是不可重入函数。
2、常见线程情况
- 常见线程不安全情况
- 不保护共享变量的函数
- 函数状态随着被调用,状态发生变化的函数
- 返回指向静态变量指针的函数
- 调用线程不安全函数的函数
- 常见线程安全情况
- 每个线程对全局变量或静态变量只有读权限没有写权限
- 类或接口对于线程来说是原子操作
- 多个线程之间的切换不会导致该接口的执行结果存在二义性
3、常见重入情况
- 常见不可重入情况
- 调用了 malloc 或 new 函数,因为 malloc 函数是用全局链表来管理堆的
- 调用了标准 IO 库函数,标准 IO 库中很多实现都以不可重入的方式使用全局数据结构
- 可重入函数体内使用了静态的数据结构
- 常见可重入情况
- 不使用全局和静态变量
- 不使用 malloc 或 new 出来的空间
- 不调用不可重入函数
- 不返回静态或全局数据,所有数据都由函数的调用者提供
- 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据
4、可重入与线程安全
- 联系
- 函数可重入就代表着线程安全
- 函数不可重入,那就不能由多个线程使用,有可能引发线程安全问题
- 如果一个函数中有全局变量,那么这个函数既是不可重入的又不是线程安全的
- 区别
- 可重入函数是线程安全函数的一种
- 线程安全不一定是可重入的,但可重入的一定是线程安全的
- 如果将对临界资源的访问加上锁,那么这个函数是线程安全的,但如果这个重入函数的锁还没释放则会产生死锁,因此是不可重入的
5、死锁
(一)概念
死锁是指在一组进程或线程中的各个进程或线程均占有不会释放的资源,但因互相申请被其他进程或线程所占用的不会释放的资源而处于的一种永久等待的状态。
死锁都是人为产生的,我们可以规避掉的。
(二)死锁的四个必要条件
- 互斥条件:一个资源只能被一个执行流使用
- 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:一个执行流已获得的资源在未使用完之前,不能强行剥夺
- 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系



