【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都陷入了一直的等待中。

死锁四个必要条件

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

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

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

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

避免死锁

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

相关推荐
华科大胡子6 天前
条款16:保证const成员函数的线程安全
互斥锁·线程安全·modern c++·const成员函数·原子变量
j7~7 天前
【Linux】二十七.线程篇四《Linux多线程编程:线程互斥(互斥量的底层到封装)、线程安全和冲入、死锁》---详解
linux·开发语言·c++·线程安全·死锁·线程互斥·重入
其实防守也摸鱼16 天前
GitHub开源项目破圈方法论:从技术自嗨到生态共赢
服务器·数据库·学习·开源·github·命令行·linux系统
其实防守也摸鱼16 天前
前端应用的离线暂停更新策略:构建稳定可靠的渐进式部署方案
服务器·前端·数据库·学习·ai·命令行·linux系统
同勉共进20 天前
记一例 vibe coding + gcc bug 导致的线程池死锁问题
c++·线程池·gcc·死锁·vibe coding
想你依然心痛20 天前
【共创季稿事节】HarmonyOS 7.0 NAPI 实战:C/C++ 原生模块开发与性能加速
内存管理·线程安全·异步任务·napi·harmonyos 7.0·c++桥接·性能加速
是个西兰花23 天前
Linux:死锁与生产者消费者模型解析
linux·运维·服务器·c++·死锁·生产者消费者模型
Joy-鬼魅23 天前
凝思磐石rocky_os_4.2.40安装教程
linux系统·rocky_4.2.40·静思磐石
是个西兰花24 天前
Linux:深入解析Linux线程原理与实现
linux·运维·c++·线程·互斥锁
rebibabo1 个月前
Java高并发底层原理(二十四)—— 线程中断如何让任务安全停止
线程安全·线程中断·java并发·协作式停止·线程池关闭·中断标记