关于c++:C面试八股文如何避免死锁

某日二师兄加入XXX科技公司的C++工程师开发岗位第31面:

面试官:什么是锁?有什么作用?

二师兄:在C++中,锁(Lock)是一种同步工具,用于爱护共享资源,避免多个线程同时拜访,从而防止数据竞争和不统一。

面试官:有哪些锁?

二师兄:从品种上分,能够分为一般锁、读写锁、递归锁等品种。

二师兄:从实现上分,能够分为互斥锁、自旋锁、信号量、条件变量等。

面试官:互斥锁如何应用?

二师兄:在C++11之前,C++便准层面并没有定义锁,锁的利用要依赖于平台。Linux下应用pthread库中的mutex

#include <pthread.h>
pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex_);
//被爱护的区域
pthread_mutex_unlock(&mutex_);

二师兄:C++11引入了std::mutex,对立了各个平台上互斥锁的应用:

#include <mutex>
std::mutex mutex_;
mutex_.lock();
//被爱护的区域
mutex_.unlock();

面试官:pthread_mutexstd::mutex有没有非阻塞的api

二师兄:有的,别离是pthread_mutex_trylock()try_lock(),当获取不到锁时这两者并不阻塞以后线程,而是立刻返回。须要留神的是,当pthread_mutex_trylock()获取到锁时返回0,而std::mutex::try_lock()办法获取不到锁时返回false

面试官:std::lock_guardstd::unique_lock用过吗?

二师兄:用过。

面试官:两者有什么相同点和不同点?

二师兄:相同点是两者都应用RAII(资源获取即初始化)技术实现的锁,反对主动上锁,主动解锁。

二师兄:不同点次要包含三个方面:

1.灵活性:std::unqiue_lock的灵活性要高于std::lock_guradstd::unique_lock能够在任何工夫解锁和锁定,而std::lock_guard在结构时锁定,在析构时解锁,不能手动管制。

2.所有权:std::unique_lock反对所有权转移,而std::lock_gurad不反对。

3.性能:因为std::unique_lock的灵活性更高,它的性能可能会略微低一些。

面试官:能实现一个lock_gurad吗?

二师兄:我尝试一下:

class lock_guard
{
    explicit lock_guard(std::mutex& m):mutex_(m)
    {
        mutex_.lock();
    }
    ~lock_guard()
    {
        mutex_unlock();
    }
private:
    std::mutex& mutex_;
};

面试官:为什么会产生死锁?

二师兄:当过程A持有锁1申请锁2,过程B持有锁2申请锁1时,两者都不会开释本人的锁,两者都须要对方的锁,就会造成死锁。当然事实中可能比这要简单,但原理是雷同的。

面试官:如何防止死锁?

二师兄:次要从以下几个方面动手:

1.防止循环期待,如果须要在业务中获取不同的锁,保障所有业务依照雷同的程序获取锁。

2.应用超时锁,当锁超时时,主动开释锁。

3.应用try_lock,当锁被占用时,返回false并继续执行。

4.锁的粒度尽量要小,只爱护竟态数据而不是整个流程。

面试官:晓得adopt_lock_t/defer_lock_t/try_to_lock_t这三种类型的用法吗?

二师兄:额。。不晓得。。

面试官:好的,回去等告诉吧。

让咱们来看看最初一个问题:

晓得adopt_lock_t/defer_lock_t/try_to_lock_t这三种类型的用法吗?

adopt_lock_t/defer_lock_t/try_to_lock_t都是空类,次要示意std::lock_guradstd::unqiue_lock的默认结构中的操作:

adopt_lock_t:默认互斥量已被以后线程锁定,不应用lock()办法对互斥量加锁:

std::mutex mtx_;
mtx_.lock();    //lock
{
    std::lock_guard<std::mutex> lock_(mtx_,std::adopt_lock);    //这里默认以后线程曾经对mtx_加过锁
    ...
}//unlock

defer_lock_t:尽管我领有了std::mutex的援用,然而在构造函数中并不调用lock()办法对互斥量加锁:

std::mutex mtx_;
{
    std::unique_lock<std::mutex> ulock_(mtx_,std::defer_lock);    //这里并没有加锁
    ulock_.lock();
    if(ulock_.owns_lock())
    {
        //locked
    }else
    {
        //unlocked
    }
}//if locked,unlock

try_to_lock_t:在构造函数执行是并不是应用lock()办法加锁,而是应用try_lock()办法加锁:

std::mutex mtx_;
{
    std::unique_lock<std::mutex> ulock_(mtx_,std::try_to_lock);    //这里mtx_如果没有被锁定,则加锁胜利,否则加锁失败
    if(ulock_.owns_lock())
    {
        //locked
    }else
    {
        //unlocked
    }
}//if locked,unlock

adopt_lock_t能够用于std::lock_guradstd::unique_lock,而defer_lock_t/try_to_lock_t只能用于std::unique_lock

关注我,带你21天“精通”C++!(狗头)

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理