【Linux系统】线程安全与死锁问题

前言:

上文我们实现了一个简单线程池并且还设计了线程池的单例模式【Linux实战 】Linux 线程池的设计、实现与单例模式应用-CSDN博客

本文我们来看看,关于线程安全与死锁的问题。


线程安全与重入问题

概念

**线程安全:**就是多个线程在访问共享资源时,能够正确的执行,不会相互干扰或破坏彼此的执行结果。一般情况下,多个线程并发访问一段只有局部变量的代码时,不会出现不同的结果。但是对全局变量或静态变量而言,在没有锁保护的前提下,很容易出现问题。

**重入:**同一个函数被不同的执行流调用,当一个执行流还没有执行完这个函数,另一个执行流就开始执行了这个函数,我们称之为重入,既一个函数多个执行流同时调用。当重入后函数的运行结果不会出现问题,我们称做可重入函数。反之,为不可重入函数。

常见线程不安全情况:

不保护共享变量的函数

函数状态随着被调用,状态发生变化的函数

返回指向静态变量指针的函数

调用线程不安全函数的函数

常见不可重入的情况:

调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的

调用了标准IO库函数,标准IO库的函数很多都是以不可重入的方式设计的

在可重入函数中使用了静态的数据结构

总结

函数是可重入的,那就是线程安全的!而线程是安全的,其函数不一定是可重入的。

思考

STL的容器是否线程安全?

**不安全。**因为STL的设计初衷就是堆性能极致的开发,而一旦涉及到加锁保证安全的环节,其性能就会大打折扣,所以STL是默认是不安全的。在多线程的环境下需要我们自己来保证安全。

智能指针是否安全?

安全。

对于unique_ptr,由于只在当前的代码块中生效,所以不涉及到线程安全问题。

对于shared_ptr,多个对象需要共用一个引用计数,所以会存在线程安全的问题。但是标准库在实现时考虑到了这个问题,让share_ptr的引用计数采用原子性的计数方式,解决了这一问题。


死锁问题

死锁:指在一组进程中的各个进程均占用不会释放的资源,但因互相申请被其他进程不会释放的资源而处于一种永久等待的状态。

申请一把锁是原子的,但申请两把锁是就不一定了。

当线程之间互相申请对方持有的锁,但不释放自己的锁时,就会造成死锁问题。

线程A申请线程B时,B一直不释放,A将会一直进行等待。同样的线程B申请线程A,A一直不释放,B也会一直进行等待。于是线程AB都陷入了一直的等待中。

死锁四个必要条件

互斥条件: 一个资源每次只能被一个执行流使用。

请求与保持: 一个执行流因请求而阻塞时,对已获得的资源保持不放。

不剥夺: 一个执行流获得资源,在未使用完之前,不得被强行剥夺。

循环等待: 若没有申请到资源则进行等待,若干执行流之间形成了头尾相连的循环等待的关系。

避免死锁

想要避免死锁很简单。只需要破坏四个必要条件中的一个即可!

相关推荐
总有刁民想爱朕ha3 天前
飞牛NAS小白部署教程:从0到1搭建你的私有云存储
linux系统·飞牛nas·nas文件存储
_OP_CHEN9 天前
【从零开始的Qt开发指南】(二十)Qt 多线程深度实战指南:从基础 API 到线程安全,带你实现高效并发应用
开发语言·c++·qt·安全·线程·前端开发·线程安全
橘颂TA11 天前
【Linux】死锁四条件的底层逻辑:从锁冲突到 STL 组件的线程安全实践(Ⅵ)
linux·运维·服务器·c++·死锁
小毅&Nora11 天前
【Java线程安全实战】⑨ CompletableFuture的高级用法:从基础到高阶,结合虚拟线程
java·线程安全·虚拟线程
栗子叶12 天前
JVM 内存溢出和死锁检测
jvm·调优·死锁
武藤一雄14 天前
C# 关于多线程如何实现需要注意的问题(持续更新)
windows·后端·microsoft·c#·.net·.netcore·死锁
我在人间贩卖青春16 天前
线程同步之互斥量
互斥锁·线程同步·互斥量
橘色的喵17 天前
全局锁策略:通过有序获取与超时保护构建无死锁系统
linux·死锁
就这个丶调调17 天前
Java ConcurrentHashMap源码深度解析:从底层原理到性能优化
java·并发编程·源码分析·线程安全·concurrenthashmap
小毅&Nora19 天前
【Java线程安全实战】③ ThreadLocal 源码深度拆解:如何做到线程隔离?
线程安全·threadlocal·jdk源码