一、手撕
1.手写一个可能发生死锁的场景
mutex mtx1,mtx2;
void thread1(){
unique_lock〈mutex〉lock1(mtx1);unique_lock〈mutex〉lock2(mtx2);
}
void thread2(){
unique_lock〈mutex〉lock1(mtx2);unique_lock〈mutex〉lock2(mtx1);
}
intmain(){
thread t1(thread1);
thread t2(thread2);
t1.join() ;t2.join();}
死锁解决的方法一 两个使用相同的申请资源的顺序
死锁解决的方法二 使用延迟申请锁,然后一次申请两把锁
void thread1(){
unique_lock〈mutex〉lock1(mtx1,defer_lock);
unique_lock〈mutex〉lock2(mtx2,defer_lock);
lock(lock1,lock2);
}
这里要记得我们平时使用的这些互斥锁都是线程粒度的,如果是 fork,父子两个进程会有独立的 mtx 变量
2.写一个优先队列支持 add,poll,remove
思路 使用数组模拟堆,每个节点是以当前节点为根的二叉树的最大的节点
class MaxHeap{
public:
vector<int>m_arr;
void siftup(int index){
while((index-1)/2>0&&m_arrindex>m_arr(index-1)/2){swapm_arrindexm_arr(index-1)/2;
index=(index-1)/2;}
}
void siftdown(int index){
int n=m_arr.size ();
while(2*index+1<n){
int largest =index ;
if (m_arr 2\*index+1>m_arr largest)largest=2*index+1;
if (2*index+2<n&&m_arr2\*index+2>m_arr largest)largest=2*index+2;
if (index !=largest)swap(m_arr index,m_arrlargest);else break;
}
然后实现的过程中,add 是插入在末尾,然后 siftup 最后一个,poll 是交换第一个和最后一个,popBack 然后 siftdown 第一个
二、八股
1.kafka 任务堆积怎么排查
从生产者,broker,消费者这三个方面考虑
第一个考虑生产者相对消费者速度,判断是否哪个有突然上涨,对于消费者要判断消费者和 partition 数量,消费者慢查询,IO 瓶颈,cpu 瓶颈
2.分布式锁的几种实现
使用 Redis 的 set nx px 结合 lua 脚本判断和释放
使用数据库的事务和原子性插入唯一索引 释放就是删除
使用数据库的行锁作为
使用 ZooKeeper 的临时节点判断是不是自己得到锁
3.harness 解决随机性各个环节对随机性的容忍度以及加固方法
从意图理解,规划,工具选择,参数校验,工具执行,观测结果,最终结果几个维度去考虑
总结,对于 mutex 之前从来没理解过是什么粒度的,事实上 fork 会复制,底层,所以它是进程独有的,不是进程粒度的控制,面试官在面试的时候还提示过我,对于优先队列实现,不是很熟悉。