[高并发服务器]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=_idMapTimerTaskid.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);
}
相关推荐
tg_xianheyun4 小时前
CDN节点分布如何影响网页加载速度和用户体验
服务器·cdn加速·全球访问优化
lsh曙光4 小时前
延时at指令和定时cron指令
linux·服务器·网络
圆山猫4 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
布鲁飞丝5 小时前
vivo Pulsar 万亿级消息处理实践()-Ansible运维部署
运维·ansible
XR1234567885 小时前
企业全光网络架构选型技术白皮书:从物理层到运维层的全链路分析
运维·网络·架构
似的8355 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
HiDev_5 小时前
【非标自动化】2、认识元器件(直线模组)
运维·自动化
夏殇之殁6 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
龙仔7256 小时前
人大金仓 KingbaseES V8 只读账号创建完整运维笔记
运维·笔记·sql·人大金仓
我不管我就要叫小猪6 小时前
嵌入式Linux----网络通信
linux·运维·服务器