服务内容
- c++后台服务, 接口接收数据同步(每次只能可能有一个请求在执行)。
引发异常现象
- 线上版本服务一直正常执行,突然有一天服务接收不到请求了。前端所有请求都收不到了。
解决思路
- 第一次出现。运营说已经半个小时无法操作了。慌得一批,赶紧查看,只发现后台接收不到数据了。不管了先重启服务。重启了,又一切正常了。跟运营小姐姐说,好了但是我还不知道原因。
- 开始怀疑是框架内网关处理的问题,其他服务有没有问题。先不管了还有很多事情没做,先做其他的。
- 隔一天第二次出现。还是怀疑框架内网关有问题。先让框架的同事查看下,框架的同事说没有问题我先重启了保证客户能用。
- 开始讨论。出现这种问题的原因大概率是死锁了。因为每次只有一个请求能处理,现在是所有的请求都收不到了,也就是说又一次的请求没有返回,这才会导致其他的请求无法接受。开始逐一排查死锁问题。花了一天全都查了一遍没有明显的死锁问题。想不通,下班了回去再看,郁闷。回家的路上骑着小电驴回顾一天的死锁。想到程序中有一个服务重置的机智。这个地方会clear掉所有的数据(数据结构为std::map<int,struct>,struct中有一个std::mutex),会不会出现我正在遍历map的value,同时另外一个线程正好执行了clear。这就会导致我遍历的map的mutex是一个无效对象,从而导致死锁。开心,回去测试一下。
上测试代码
#ifndef __TEST_SOME_HPP__
#define __TEST_SOME_HPP__
#include <iostream>
#include <mutex>
#include <map>
#include "BaseFunc.h"
#include <thread>
#include <list>
using namespace std;
#define aaaa(a) #a
#define aabb(a,b) a##b
void run_TestSome()
{
int64_t iAccID;
cout << iAccID << endl;
}
#pragma region 测试mutex
struct StructMutex_s
{
std::mutex _mux;
std::map<int,int> _mapData;
void add(int i, int j) {
std::unique_lock<std::mutex> lck(_mux);
_mapData[i] = j;
}
};
std::map<int, StructMutex_s> g_mapStructMutexData;
void printStructMutexData()
{
for (auto& item : g_mapStructMutexData)
{
basefunc::Sleep(600);
std::unique_lock<std::mutex> lck(item.second._mux);
for (auto& data : item.second._mapData) {
cout << data.first <<";"<<data.second << endl;
}
}
}
void clearStructMutexData()
{
basefunc::Sleep(1000);
g_mapStructMutexData.clear();
cout << "clear finish" << endl;
}
void run_TestStructMutex(){
for (int i = 0; i < 10; ++i) {
g_mapStructMutexData[i].add(i, i+1);
}
std::list<std::thread> listThread;
std::thread t1(
[&](){
clearStructMutexData();
});
std::thread t2(
[&](){
printStructMutexData();
});
t1.join();
t2.join();
}
#pragma endregion
#endif
#include "test.hpp"
int main()
{
run_TestStructMutex();
return 0;
}
总结
- 死锁问题不一定是显示的lock之后没有unlock,还有可能互斥相已经不存在了。