[高并发服务器]DEBUG日志

1.客户端主动断开TCP连接,引发的段错误

2.定时任务执行后,引发的段错误

2.1.问题描述

在服务器启动非活跃连接超时销毁后,

当定时任务执行时,

触发了段错误;

下面是相关日志

bash 复制代码
//相关日志:
//设定的定时任务为Connection::releaseInLoop()
[DEBUG][2025-12-19 15:07:08]TimerTask::~TimerTask(): execute timer task,id:1
[DEBUG][2025-12-19 15:07:08]TimerTask::~TimerTask(): execute timer task,id:2
[DEBUG][2025-12-19 15:07:08][tid=140399404377664]执行Connection::releaseInLoop(),conn_id=1
[DEBUG][2025-12-19 15:07:08][tid=140399412770368]执行Connection::releaseInLoop(),conn_id=2
Segmentation fault (core dumped)

2.2.问题定位

下面是TimerTask::~TimerTask()的具体实现

cpp 复制代码
TimerTask::~TimerTask()
{
    //如果定时任务没有被取消
    if(false == _isCanceled) 
    {
        lg(DEBUG,"TimerTask::~TimerTask(): execute timer task,id:%lu",_id);
        _taskCb();//执行定时任务
    }
    //lg(DEBUG,"TimerTask::~TimerTask(): _deleteCb() ,id:%lu",_id);

    //将id->TimerTask的映射关系从TimerWheel​​​​​​​::_idMapTimerTask内移除
    _deleteCb();
}

下面是Connection::releaseInLoop()的具体实现

cpp 复制代码
void Connection::releaseInLoop()
{
#ifdef DEBUG
    std::thread::id gtid=std::this_thread::get_id();
    std::ostringstream oss;
    oss << gtid;
    std::string tid=oss.str();
    lg(DEBUG,"[tid=%s]执行Connection::releaseInLoop(),conn_id=%lld",tid.c_str(),getId());
#endif
    //assert(CONNECTED == _status ||DISCONNECTING == _status );
    //修改连接状态
    _status = DISCONNECTED;

    //取消该连接的定时任务
    _eventLoop->cancelTimerTask(_id);

    //从epoll中移除该channel
    _channel.remove();

    //关闭描述符
    _socket.close();

    lg(DEBUG,"[tid=%s]_connId=%lld,Connection::releaseInLoop() 1",tid.c_str(),getId());

    //调用用户设置的回调
    if(_closeCb) _closeCb(shared_from_this());

    // std::thread::id gtid=std::this_thread::get_id();
    // std::ostringstream oss;
    // oss << gtid;
    // std::string tid=oss.str();
    lg(DEBUG,"[tid=%s]_connId=%lld,Connection::releaseInLoop() 2",tid.c_str(),getId());

    //调用组件本身设置的回调
    if(_serverCloseCb) _serverCloseCb(shared_from_this());

    lg(DEBUG,"[tid=%s]_connId=%lld,Connection::releaseInLoop() 3",tid.c_str(),getId());
    
}

Connection::releaseInLoop()没有执行后续的DEBUG日志代码,

说明问题出现在下面这段区间,

cpp 复制代码
    //assert(CONNECTED == _status ||DISCONNECTING == _status );
    //修改连接状态
    _status = DISCONNECTED;

    //取消该连接的定时任务
    _eventLoop->cancelTimerTask(_id);

    //从epoll中移除该channel
    _channel.remove();

    //关闭描述符
    _socket.close();

后续在cancelTimerTask(_id)定位到如下内容

cpp 复制代码
void TimerWheel::cancelTaskToLoop(uint64_t id)
{
    //lg(DEBUG,"TimerWheel::cancelTaskToLoop(uint64_t id) called");
    if(exist(id) == false) return ; //判断id是否在TimerWheel​​​​​​​::_idMapTimerTask内
    //lg(DEBUG,"TimerWheel::cancelTaskToLoop(uint64_t id) 1");
    std::shared_ptr<TimerTask> ptr=_idMapTimerTask[id].lock();
    //lg(DEBUG,"TimerWheel::cancelTaskToLoop(uint64_t id) 2 ,ptr==nullptr:%d",(ptr==nullptr));
    ptr->cancel();
    //lg(DEBUG,"TimerWheel::cancelTaskToLoop(uint64_t id) over");
}   

上述代码的**ptr->cancel();**是引发段错误的原因

2.3.问题产生原因分析

在时间轮TimerWheel模块的实现中,

有如下成员;

cpp 复制代码
    /// @brief 时间轮数组
    std::vector<std::list<std::shared_ptr<TimerTask>>> _wheel;

    /// @brief id->timeTask映射表
    std::unordered_map<uint64_t,std::weak_ptr<TimerTask>> _idMapTimerTask;

当_wheel内的定时任务TimerTask结构体 调用析构函数执行定时任务(即Connection::releaseInLoop())时,

在此之前对应的shared_ptr的引用计数已经变为0 ,置为nullptr,且被释放;

因为**exist(id)**的返回结果为true,

因此会执行std::shared_ptr<TimerTask> ptr=_idMapTimerTask[id].lock()(这句代码位于Connection::releaseInLoop()中的_eventLoop->cancelTimerTask(_id);的执行流程内);

获取到的ptr的值为nullptr,

从而导致段错误

2.4.问题解决方案

修改TimerTask::~TimerTask(),在定时任务执行前移除id->TimerTask的映射关系,如下;

cpp 复制代码
TimerTask::~TimerTask()
{
    //将id->TimerTask的映射关系从TimerWheel​​​​​​​::_idMapTimerTask内移除
    _deleteCb();

    //如果定时任务没有被取消
    if(false == _isCanceled) 
    {
        lg(DEBUG,"TimerTask::~TimerTask(): execute timer task,id:%lu",_id);
        _taskCb();//执行定时任务
    }
    //lg(DEBUG,"TimerTask::~TimerTask(): _deleteCb() ,id:%lu",_id);
}
相关推荐
CN-Dust10 分钟前
【C++】for循环例题专题
java·c++·算法
搞科研的小刘选手15 分钟前
【高届数传感机电会议】第十二届传感器、机电一体化和自动化系统国际学术研讨会(ISSMAS 2026)
运维·人工智能·自动化·控制·传感器·传感·机电
IOT那些事儿22 分钟前
Qt5 VSCode调试
c++·vscode·mingw·qt5
楼兰公子32 分钟前
读取rpi摄像头
linux·服务器·算法
c++之路32 分钟前
C++ 多线程
开发语言·c++
李景琰37 分钟前
Debian12安装配置Mqtt之EMQX
linux·运维·服务器
SimLine芯见38 分钟前
专为空管环境打造的KVM切换器,满足主备自动化高速无缝切换需求
运维·自动化
测试员周周39 分钟前
【AI测试系统】第1篇:LangGraph 实战:用 State Graph 搭建 AI测试流水线(4 步编排 + RAG 增强 + 完整代码)
linux·windows·python·功能测试·microsoft·单元测试·多轮对话
不做无法实现的梦~1 小时前
PX4 机载电脑 Linux 环境安装、串口、网络、ROS 完整配置
linux·运维·网络
嵌入式×边缘AI:打怪升级日志1 小时前
嵌入式Linux开发(了解交叉编译工具链的组成)
java·linux·运维