目录
死锁
概念
死锁的四个必要条件
避免死锁的发生
自旋锁
概念
pthread_spin_init(初始化自旋锁)
pthread_spin_lock(申请自旋锁)
pthread_spin_unlock(释放自旋锁)
pthread_spin_destroy(销毁自旋锁)
死锁
概念
死锁(Deadlock)是指两个或多个进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,这些进程将无法继续推进。
举例来说,现在有线程 A 和线程 B,这两个线程都需要同时持有互斥锁 1 和互斥锁 2 才可以向后推进,访问临界资源,此时 线程 A 拿到了互斥锁 1,线程 B 拿到了互斥锁 2,两个线程都申请对方持有的锁,但是谁都不肯释放锁,导致谁都无法同时持有两把锁,那么这两个线程就互相等待,都不向后推进了,导致死锁!
死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个执行流使用。
- 占有并等待条件:一个进程必须已经持有至少一个资源,并等待获取当前被其他进程占用的额外资源。
- 不可剥夺条件:资源不能从进程那里强行夺取,只有拥有该资源的进程可以主动释放资源。
- 循环等待条件:若干执行流之间形成一种头尾相连的循环等待资源的关系。即存在一组等待的进程{P1, P2, ..., PN},其中每个Pi正在等待由Pi+1持有的资源,PN等待由P1持有的资源。
避免死锁的发生
- 只要破坏死锁的四个必要条件之一,就可以避免死锁!
- 尽量缩短持有锁的时间,只在绝对必要的时候才获取锁,并尽快释放。
- 确保所有线程总是按照相同的顺序获取锁,以防止循环等待。
- 要求每个进程在开始执行之前一次性申请所有需要的资源。这种方法可以完全避免死锁,但可能导致资源利用率低下。
自旋锁
概念
自旋锁(Spinlock)是一种同步机制,主要用于多处理器系统中保护共享资源。与传统的互斥锁不同,当一个线程尝试获取已经被占用的自旋锁时,它不会立即进入睡眠状态(阻塞),而是会不停地循环检查锁的状态(忙等待或自旋),直到锁被释放。这种方式可以减少上下文切换带来的开销,但在锁持有时间较长的情况下,可能会浪费大量的CPU周期。
自旋锁最适合用于锁持有时间非常短暂的情形,例如保护少量数据或执行简单操作时。在这些情况下,上下文切换的成本可能超过自旋等待的成本。此外,在实时系统中,为了确保响应时间尽可能短,也常常使用自旋锁。
pthread_spin_init(初始化自旋锁)
#include <pthread.h>int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
lock
:指向要初始化的自旋锁对象的指针。
pshared
:指示该自旋锁是否可以在进程间共享。取值有两种:
PTHREAD_PROCESS_PRIVATE
(0):默认值,表示该锁只能被同一进程内的线程共享。PTHREAD_PROCESS_SHARED
(非0):表示该锁可以被多个进程中的线程共享。
返回值
- 成功时返回
0
。- 如果发生错误,则返回一个正整数错误码,并且不会初始化自旋锁。
pthread_spin_lock(申请自旋锁)
#include <pthread.h>int pthread_spin_lock(pthread_spinlock_t *lock);
lock
: 指向要获取的自旋锁对象的指针。
返回值:
- 成功时返回
0
。- 如果发生错误,则返回一个正整数错误码。
pthread_spin_unlock(释放自旋锁)
#include <pthread.h>int pthread_spin_unlock(pthread_spinlock_t *lock);
lock
: 指向要释放的自旋锁对象的指针。
返回值:
- 成功时返回
0
。- 如果发生错误,则返回一个正整数错误码。
pthread_spin_destroy(销毁自旋锁)
#include <pthread.h>int pthread_spin_destroy(pthread_spinlock_t *lock);
lock
: 指向要销毁的自旋锁对象的指针。
返回值:
- 成功时返回
0
。- 如果发生错误,则返回一个正整数错误码。