乐趣区

关于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++!(狗头)

退出移动版