[高并发服务器]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);
}
相关推荐
nbsaas-boot2 小时前
SQL Server 存储过程设计规范(事务与异常处理)
linux·数据库·设计规范
天赐学c语言2 小时前
12.19 - 买卖股票的最佳时机 && const的作用
c++·算法·leecode
lx7416026983 小时前
百度网盘bypy使用
服务器
Jason_zhao_MR3 小时前
米尔RK3506核心板SDK重磅升级,解锁三核A7实时控制新架构
linux·嵌入式硬件·物联网·架构·嵌入式·嵌入式实时数据库
为什么不问问神奇的海螺呢丶3 小时前
服务器巡检报告-基于categraf 采集数据-存入Prometheus-写入mysql后生成报告
服务器·mysql·prometheus
网硕互联的小客服3 小时前
遇到网站500内部服务器错误如何处理?如何预防这样的问题发生?
运维·服务器·安全
叮咚侠3 小时前
Ubuntu 24.04.3 LTS 中 vdb 的 UUID 永久挂载没有显示的磁盘的操作步骤
linux·运维·ubuntu·挂载磁盘
GAOJ_K3 小时前
滚柱导轨中的密封件如何判断是否需更换?
运维·人工智能·科技·自动化·制造
.小墨迹4 小时前
C++学习之std::move 的用法与优缺点分析
linux·开发语言·c++·学习·算法·ubuntu