共计 2376 个字符,预计需要花费 6 分钟才能阅读完成。
某日二师兄加入 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_mutex
和std::mutex
有没有非阻塞的api
?二师兄:有的,别离是
pthread_mutex_trylock()
和try_lock()
,当获取不到锁时这两者并不阻塞以后线程,而是立刻返回。须要留神的是,当pthread_mutex_trylock()
获取到锁时返回0
,而std::mutex::try_lock()
办法获取不到锁时返回false
。面试官:
std::lock_guard
和std::unique_lock
用过吗?二师兄:用过。
面试官:两者有什么相同点和不同点?
二师兄:相同点是两者都应用
RAII
(资源获取即初始化)技术实现的锁,反对主动上锁,主动解锁。二师兄:不同点次要包含三个方面:
1. 灵活性:
std::unqiue_lock
的灵活性要高于std::lock_gurad
,std::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_gurad
和std::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_gurad
和std::unique_lock
,而 defer_lock_t/try_to_lock_t
只能用于std::unique_lock
。
关注我,带你 21 天“精通”C++!(狗头)