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_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++!(狗头)
C++面试八股文:如何避免死锁?的更多相关文章
- 《面试八股文》之kafka21卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是moon,最新一篇面试八股文系 ...
- 《面试八股文》之 Redis 16卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. redis 作为 ...
- 《面试八股文》之 JVM 20卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. <面试八股 ...
- 一天吃透MySQL面试八股文
什么是MySQL MySQL是一个关系型数据库,它采用表的形式来存储数据.你可以理解成是Excel表格,既然是表的形式存储数据,就有表结构(行和列).行代表每一行数据,列代表该行中的每个值.列上的值是 ...
- 一天吃透JVM面试八股文
什么是JVM? JVM,全称Java Virtual Machine(Java虚拟机),是通过在实际的计算机上仿真模拟各种计算机功能来实现的.由一套字节码指令集.一组寄存器.一个栈.一个垃圾回收堆和一 ...
- 这可能是最全面的MySQL面试八股文了
什么是MySQL MySQL是一个关系型数据库,它采用表的形式来存储数据.你可以理解成是Excel表格,既然是表的形式存储数据,就有表结构(行和列).行代表每一行数据,列代表该行中的每个值.列上的值是 ...
- 这可能是最全面的Redis面试八股文了
Redis连环40问,绝对够全! Redis是什么? Redis(Remote Dictionary Server)是一个使用 C 语言编写的,高性能非关系型的键值对数据库.与传统数据库不同的是,Re ...
- 三天吃透Java虚拟机面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
- 三天吃透Redis面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
- 三天吃透MySQL面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
随机推荐
- [MyBatis]MyBatis系列:模糊查询的4种实现方式【待完善】
背景 客户现网遇到的1个子问题. 方案 LIKE + Concat(strA, strB) ... 参考文献 MyBatis系列:模糊查询的4种实现方式
- 11.spring security 认证和授权简单流程了解
1.总结:昨天主要是对WebSecurityConfigurerAdaptor的三个函数的区分以及了解了spring security的认证和授权流程:再就是动手使用了下thymeleaf和freeM ...
- 五月十四号java基础知识点
class Person{ private String name; private int age; public Person(String name,int age){ this.name = ...
- python 类中的属性排序
可以使用Python中的类(class)来定义一个包含姓名和年龄的类.以下是一个示例代码: class Person: def __init__(self, name, age): self.name ...
- $el,$nextTick,$set
this.$el this.$el DOM的根元素 => 是一个完全唯一的 $el 直到组件挂载完成 (mounted) 之前都会是 undefined. 对于单一根元素的组件,$el 将会指向 ...
- 分布式缓存--Redis
目录 一.单点Redis的问题 二.Redis持久化 2.1 RDB持久化 2.1.1 单机安装Redis 2.1.2 RDB内部机制 2.1.3 RDB异步持久化 2.1.14 RDB的缺点 2.2 ...
- 笔记:C++学习之旅---面向对象程序的设计1
笔记:C++学习之旅---面向对象程序的设计1 面向对象的主要特征 1.抽象 2.封装 3.继承 4.多态 抽象:将程序的每一部分都看作一个抽象的对象,即程序有一组抽象的对象组成的更复杂点,这些对象根 ...
- AGC061 F Perfect String
毒瘤出题人,史诗加强 AGC 的 F-- 然而我连原题都不会,所以只学了原题做法. 翻译一下题意就是给定一张循环网格图,求经过 \((0,0)\) 的闭合回路条数. 由于网格图中每一个位置都等价,所以 ...
- 2022-03-31:有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱, 以及不同程度的安静值(quietness) 为了方便起见,我们将编号为 x 的人简称为
2022-03-31:有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱, 以及不同程度的安静值(quietness) 为了方便起见,我们将编号为 x 的人简称为 ...
- 小知识:设置archive_lag_target参数强制日志切换
为客户测试一个ADG场景问题,发现测试环境的日志切换频率过低,总是需要定期手工切换,这非常影响测试心情. 实际上,可以设置archive_lag_target参数强制日志切换. 比如设置: alter ...