各种锁机制
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循环,未被唤醒的线程继续等待下一次被唤醒。

查看12道真题和解析