【C++】自旋锁、读写锁、可重入锁与不可重入锁的简单理解

自旋锁(spinlock):当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成忙等busy-waiting,消耗CPU资源。
在之前的博客中,我们了解过互斥锁,互斥锁实际上是一种sleep-waiting的锁,当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将被阻塞放入等待队列,不会造成忙等现象,CPU可以去处理其他任务,不会浪费CPU资源。

//自旋锁互斥实现
class spinlock_mutex
{
    std::atomic_flag flag;
public:
    spinlock_mutex():flag(ATOMIC_FLAG_INIT) {}
    void lock()
{
    while(flag.test_and_set(std::memory_order_acquire));
}
    void unlock()
{
    flag.clear(std::memory_order_release);
}
}

读写锁(readers-writer lock):读写锁可以和读者-写者问题结合起来理解,读写锁是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则可以对共享资源进行写操作。简单来说就是一次只能有一个人写,但可以多个人一起读。
当读写锁被加了写锁时,其他线程对该锁加读锁或写锁都会被阻塞;当读写锁被加了读锁时,其他线程对该锁加读锁会成功,加写锁会被阻塞。比较适用于多读少写的场景。
可重入锁(reentrant lock):
可重入锁简单如字面而言,就是可以重新进入的锁,允许同一进程多次获取同一把锁,是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提是同一个对象或者class),这样的锁就叫做可重入锁,也叫做递归锁。

不可重入锁(non-reentrant lock):
不可重入锁与可重入锁相反,如果当前线程已经获取了该锁,那么再次尝试获取该锁时,就会出现死锁的状况,被阻塞。在这个线程解锁之前,其他线程无法用这个锁再来加锁。

可重入锁不与可重入锁的区别:不可重入锁只判断这个锁有没有被锁上,只要被锁上申请锁的线程都会被要求等待。实现起来较为简单。而可重入锁不仅要判断锁有没有被锁上,还会判断锁是谁锁上的,当就是自己锁上的时候,那么他依旧可以再次访问临界资源,并把加锁次数加一。

### 可重入的概念 可重入是一种允许同一个线程对其已持有的进行多次获取而不发生死的同步机制[^3]。这意味着如果一个线程已经持有了某把,在未释放之前,它可以继续申请相同的而不会被阻塞。 ### 工作原理 可重入通过维护一个计数器来实现其功能。每当一个线程成功获取时,计数器会增加;当线程释放时,计数器减少。只有当计数器回到零时,才会真正被释放并可供其他线程使用[^1]。这种设计使得同一线程可以在不同的嵌套调用中安全地重新进入定区域。 以下是基于 `ReentrantLock` 的简单代码示例: ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantExample { private final ReentrantLock lock = new ReentrantLock(); public void methodA() { lock.lock(); try { System.out.println("Method A acquired the lock."); methodB(); // 调用另一个方法,仍然能够持有 } finally { lock.unlock(); } } public void methodB() { lock.lock(); try { System.out.println("Method B also holds the same lock without deadlock."); } finally { lock.unlock(); } } public static void main(String[] args) { ReentrantExample example = new ReentrantExample(); example.methodA(); } } ``` 在这个例子中,`methodA` 和 `methodB` 都尝试获取同一把,但由于它是可重入,因此不会引发死问题。 ### 应用场景 可重入广泛应用于多层调用结构复杂的并发环境中。例如,在 Java 中,`synchronized` 关键字和 `ReentrantLock` 类都实现了可重入特性[^2]。这使得开发者能够在不担心死的情况下编写更灵活、更易于理解的并发控制逻辑。 #### 常见的应用场景包括但不限于: - **递归调用中的保护**:在一个函数内部可能会反复调用自己的情况下,使用可重入可以避免因重复加而导致的死。 - **分层架构下的资源共享**:多个层次之间可能存在对相同资源的竞争访问需求,此时利用可重入可以让单个线程顺利操作这些资源。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值