乐观锁与悲观锁--学习笔记

13 篇文章 0 订阅
5 篇文章 1 订阅


前言

在多线程编程当中,为了保证数据的一致性,需要使用锁机制。比如Qt中的std::mutex,在读写数据之前lock,处理完数据之后unlock。这种锁机制,我们通常称为悲观锁,即悲观的认为数据不安全,容易出错,所以在操作前夹锁,保证数据一定是多线程安全的。另外,我在看一些技术文章时,还看到一种锁:乐观锁,挺好奇的,它的机制是怎么样的?


一、悲观锁

悲观锁:每次操作数据之前加锁,每次操作数据后解锁。

1、悲观锁用例一

在Qt编程中,经常这样使用锁,利用lock_guard来管理锁,可以不用担心加锁后忘记解锁。lock_guard使用C++的对象生命周期机制,构造函数调用mutex的加锁操作、析构的时候调用mutex的解锁机制,完美的解决加解锁的管理问题。
// Acquire the mutex here with a constructor call, then release with
  // the destructor call in accordance with RAII style.
  template<typename _Mutex>
    class lock_guard
    {
    public:
      typedef _Mutex mutex_type;

      explicit lock_guard(mutex_type& __m) : _M_device(__m)
      { _M_device.lock(); }

      lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
      { } // calling thread owns mutex

      ~lock_guard()
      { _M_device.unlock(); }

      lock_guard(const lock_guard&) = delete;
      lock_guard& operator=(const lock_guard&) = delete;

    private:
      mutex_type&  _M_device;
    };
锁的应用代码如下:
//头文件
#include <mutex>

//创建mutex对象
std::mutex* m_mutex = new std::mutex;

//
{
//加锁
lock_guard<mutex> lock(m_mutex);
//操作数据
//..自动解锁
}



2、悲观锁用例二

例一是使用自动管理锁,这里是手动管理,使用了Qt的QMutex。手动管理锁时,记得操作完数据后调用unlock,否则其他线程会一直阻塞。
//头文件
#include <qmutex.h>

//使用
QMutex mutex_;
mutex_.lock();
//操作数据
mutex_.unlock();

二、乐观锁

悲观锁一直认为数据的操作是不安全的,所以操作数据前都主动加锁,以保护数据。而乐观锁,非常乐观,觉得操作数据一直是安全的,不需要立即加锁,以提高数据操作的效率。乐观锁其实并没有使用锁,而是采用了一些业务策略来保证多线程访问数据的一致性。第一种策略是使用版本号,第二种是使用CAS算法(compare and swap比较交换法)。

1、版本号保证数据一致性

这种策略的原理是:

1、使用一个版本号来管理数据,当读取数据时,同时获取这个版本号;
2、当操作完数据后,需要写操作,则此时再获取一次数据及版本号,如果都和之前的一致,则执行写操作,更新这个数据,同时更新版本号。否则,更新失败,需重新从第一步开始重试。

通过判断版本号的方式,可以确定数据是否被其他线程修改过。如果被修改过,则此次修改操作被放弃,然后重试,直到数据成功修改为止。

2、CAS算法保证数据一致性

这种策略的原理是:
1、设需要操作的值是A;
2、给A设置一个备用变量B,使B=A;
3、新值是C;
当需要设置A的值时,先比较B和A是否相等,如果相等,则把C的值替换给A和B;如果不相等(被其他线程改变),则此次数据更新失败,重试,直到数据更新成功为止。需要说明的是,这里的比较和替换是一个原子操作,详细情况请参见:

CAS操作确保原子性


总结

悲观锁主要用于写操作频繁的场景,保证数据一定是一致的;而乐观锁主要用于读操作频繁,写操作比较少的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值