各种锁机制

1.互斥锁

1.std::mutex 
mutex mtx
mtx.lock()
mtx.unlock()
2.std::lock_guard 利用RAII技术进行上锁和解锁
声明
template<class Mutex>
class lock_guard;
构造函数
explicit lock_guard(mutex_type& m);
3.互斥锁底层实现
//1:上锁 0:解锁
 bool testAndSet(bool& mutex){
   bool value=mutex;
   mutex=true;
   return value;
}

while(testAndSet(mutex)) ; //如果上锁后有线程去获得锁,则一直while循环
/
临界区
/
mutex=0;  //解锁

2.自旋锁(独占锁)

1.实现
class SpinLock {    
public:
    void lock() 
    {
        while (flag.test_and_set(memory_order_acquire));
                //当一个线程无法获取锁时一直阻塞在while循环
    }
    void unlock() 
    {
        flag.clear(memory_order_release);
    }
private:
    std::atomic_flag flag;
};

2.应用场景
当线程无法获取锁时一直试图去获取锁(忙等待),而不是进入睡眠态,
适用于线程使用锁时间较短的场景(当线程切换开销比较大时)。

3.读写锁

1.实现 利用互斥锁实现读写锁
class RWLOCK{
public:
   RWLOCK():flag(0){}
   void readLock(){
      mtx.lock();
      while(flag<0){
         cond.wait(mtx);
      }
      ++flag;
      mtx.unlock();
   }
   void readUnlock(){
      mtx.lock();
      //最后一个读锁解锁,可以进行写锁上锁
      if(--stat==0){
          cond.notify_all();
      }
   }
   void writeLock(){
      mtx.lock();
      //只有不上锁时才能上写锁
      while(flag!=0){
         cond.wait(mtx);
      }
      flag=-1;
      mtx.unlock();
   }
   void writeUnlock(){
        mtx.lock();  
        flag = 0;  
        cond.notify_all(); // 叫醒所有等待的读和写操作  
        mtx.unlock();  
   }
private:
  atomic<int> flag; //0:无锁 >0:读锁的个数 <0:写锁
  condition_variable cond;
  mutex mtx;
};

4.条件变量

1.常用方法
std::mutex mtx;
std::condition_variable cond;
cond.wait(mtx);
cond.notify_all();
2.为何条件变量要搭配锁使用?

//消费者线程
while(queue.empty()){
    /
         1.
         ...
    /
    cond.wait(mtx);
}

//生产者线程
cond.notify_all()

假设有一个生产者线程和一个消费者线程,消费者此时进入1处,
而此时生产者线程发送唤醒信号,而消费者线程未进入wait态,
就错过了该唤醒状态,此时这个线程就永远阻塞了。
而使用锁,进入wait时就先上锁,然后把线程放入等待队列,然后释放锁,就不会错过唤醒信号。

等待队列的线程竞争锁,谁获取锁谁被唤醒,获取资源,
因此,要用while循环,未被唤醒的线程继续等待下一次被唤醒。
全部评论
太实用了,感谢分享啊
点赞 回复 分享
发布于 2022-08-04 20:20

相关推荐

10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
点赞 评论 收藏
分享
2 8 评论
分享
牛客网
牛客企业服务