向外张望的人在做梦,
向内审视的人才是清醒的。
--- 荣格 ---
我最近复习了线程安全这部分知识,将不明白的问题总结出来,并通过AI进行问答帮助我进行学习巩固。本人能力有限 ,可能有些内容不准确,望各位大佬海涵!!!
线程与线程安全知识总结
1 请简述线程安全概念与实现
线程安全指的是在多线程编程中,多个线程对临界资源进行争抢访问而不会造成数据二义或程序逻辑混乱的情况。当多个线程访问同一资源时,这些线程不会相互干扰,程序的行为仍然符合预期,不会出现数据不一致或错误的结果。
线程安全的实现,通过同步与互斥实现!
线程的同步和互斥是确保多线程程序正确执行的关键技术,具体互斥的实现可以通过互斥锁和信号量实现、而同步可以通过条件变量与信号量实现。
- 互斥锁(Mutexes):通过互斥锁可以保证同一时间只有一个线程访问共享资源,其他线程必须等待锁被释放后才能访问。
- 读写锁(Read-Write Locks):允许多个读操作同时进行,但写操作会独占锁,用于读多写少的场景。
- 条件变量(Condition Variables):允许线程在某些条件下挂起或被唤醒,常与互斥锁结合使用。
- 原子操作(Atomic Operations):提供原子性的数据操作,确保在多线程环境中对数据的修改是安全的。
- 线程局部存储(Thread-Local Storage, TLS):为每个线程提供独立的变量副本,从而避免共享。我们实现高并发内存池中有所使用!!!
2 死锁发生的必要条件和避免措施
死锁发生的四个必要条件:
- 互斥条件:资源不能被多个进程同时使用,只能由一个进程独占直到该进程释放资源。
- 占有和等待条件:进程至少持有一个资源,并且正在等待获取额外的资源,而该资源又被其他进程持有。
- 不可抢占条件:已经分配给进程的资源在未使用完毕之前不能被其他进程强行抢占。
- 循环等待条件:存在一种进程资源的循环等待链,每个进程至少持有一个资源,并等待获取下一个进程所持有的资源。
解决死锁的方法就是破坏死锁发生的必要条件,这样就可以避免死锁发生:
- 破坏互斥条件: - 尽可能使资源可共享,但这在许多情况下不可行,因为有些资源(如打印机)本质上就是互斥的。
- 破坏持有和等待条件: - 要求线程在开始执行前一次性声明所有需要的资源。- 如果无法一次性获取所有资源,线程可以在持有部分资源的情况下释放它们,然后重新尝试获取全部资源。
- 破坏非抢占条件: - 允许线程抢占资源,但这可能导致系统复杂度和不确定性增加。- 实现抢占式调度策略,可以在一定条件下强制回收资源。
- 破坏循环等待条件: - 对所有资源类型进行排序,并要求线程只能按照顺序请求资源。- 通过资源分级避免循环等待。
上面是方法理论,我们可以通过以下这些具体的方法来避免死锁:
- 资源分配策略:避免动态资源分配,而是预先分配资源。使用银行家算法来避免系统进入不安全状态。
- 锁的顺序:确保所有线程以相同的顺序请求和释放锁。
- 超时机制:如果线程在一段时间内没有获取到锁,则放弃并重新尝试。
3 请简述线程池的作用与实现原理
面试简述:
线程池通过一个线程安全的阻塞任务队列加上一个或一个以上的线程实现,线程池中的线程可以从阻塞队列中获取任务进行任务处理,当线程都处于繁忙状态时可以将任务加入阻塞队列中,等到其它的线程空闲后进行处理。
可以避免大量线程频繁创建或销毁所带来的时间成本,也可以避免在峰值压力下,系统资源耗尽的风险;并且可以统一对线程池中的线程进行管理,调度监控。
线程池项目之前的文章有详细讲过。其使用的是资源复用的思想,通过池化技术来实现:
池化技术(Pooling)是一种在计算机科学中常用的资源管理技术,其核心思想是预先分配并管理一定数量的资源,当需要使用资源时,不是每次都重新创建新的资源,而是从预先分配的资源池中取出资源进行使用,使用完毕后再归还到资源池中,以供后续重用。这种技术可以显著减少资源创建和销毁的开销,提高资源利用率,降低系统延迟。
4 简述并发编程的特性
- 原子性:C++中的原子操作保证了对共享数据的修改在多线程环境中是不可分割的,即其他线程看不到操作的一半状态,确保了数据的一致性。
- 可见性:C++通过内存模型保证,当线程对共享变量进行写操作后,其他线程能够立即看到这些修改,避免了读取到旧数据的问题。
- 有序性:C++的内存模型确保了程序中的操作按照特定的顺序执行,防止编译器和处理器对指令进行重排序,从而保证了多线程环境下的执行顺序与代码中的顺序一致。
5 信号量实现与条件变量有什么区别?
- 条件变量提供了一个pcb阻塞队列以及阻塞和唤醒线程的接口用于实现同步,但是什么时候该唤醒以及什么时候该阻塞线程由程序员进行控制,而这个控制通常需要一个共享资源的条件判断完成,因此条件变量还需要搭配互斥锁使用,来保护这个共享资源的条件判断及操作。
- 信号量提供一个pcb等待队列,以及一个实现了原子操作的对资源进行计数的计数器,通过自身计数器实现同步的条件判断,因此不需要搭配互斥锁使用,而且信号量在初始化计数为1的情况下也可以模拟实现互斥操作。
6 简述什么是线程同步,为什么需要同步
线程同步是指通过特定的机制协调多个线程的执行,使得它们能够按照一定的顺序或条件访问共享资源,避免并发执行时产生的数据竞争和状态不一致问题。
为什么需要同步:
- 防止竞态条件:当多个线程同时访问和修改同一数据时,没有适当的同步可能导致不可预测的结果。
- 保持数据一致性:同步机制确保共享数据的修改对其他线程可见,维护数据的正确性。
- 控制执行顺序:在某些情况下,需要确保某些操作按照特定的顺序执行,同步可以提供这种控制。
- 避免死锁和饥饿:合理的同步策略有助于避免线程因资源争夺而无法继续执行的情况。
版权归原作者 叫我龙翔 所有, 如有侵权,请联系我们删除。