You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程调用C++ std::list.remove()触发段错误该如何解决?

问题根因

STL标准容器默认不具备线程安全性,多个线程同时对同一个std::list执行读写、写操作时,会破坏容器内部的链表节点结构。
你遇到的段错误完全符合该场景:从栈回溯可以看到,程序调用std::list::size()时需要遍历全表计算长度(C++11之前的std::list::size是O(n)复杂度),此时另一个线程正在执行remove操作删除节点,遍历过程中访问到已经被释放的节点内存,触发访问越界。

可行解决方案

方案1:加互斥锁保护所有容器操作(最稳妥、兼容性最高)

所有对table的访问(包括读操作如size()、遍历,写操作如push_back、remove)都必须加同一把互斥锁,保证同一时间只有一个线程操作容器。
C++11及以上版本示例代码:

#include <mutex>
#include <list>

std::list<intptr_t> table;
// 全局互斥锁,专门用于保护table的所有操作
std::mutex table_mtx;

void * customer(void* vargp){
    intptr_t tid = (intptr_t)vargp;
    // 顾客就座,加锁操作容器
    {
        std::lock_guard<std::mutex> lock(table_mtx);
        table.push_back(tid);
    } // 代码块结束自动解锁,不阻塞后续业务逻辑的并行执行

    // 餐桌处业务逻辑,无需加锁,可并行执行
    // do actions at table

    // 顾客离开,加锁操作容器
    {
        std::lock_guard<std::mutex> lock(table_mtx);
        table.remove(tid);
    }
}

如果是C++03环境,可替换为pthread_mutex_t实现互斥锁,逻辑完全一致。

注意:其他代码中如果有调用table.size()、遍历table的逻辑,也必须加同一把锁,否则仍然会出现段错误。

方案2:优化删除效率(可选)

当前list::remove(tid)的复杂度是O(n),每次删除都要遍历全表。如果并发线程数较多可以优化:就座时在加锁状态下记录插入节点的迭代器,离开时直接通过迭代器调用erase删除,复杂度降为O(1)。

额外验证点

如果加锁后仍然出现段错误,可检查:

  • 是否有遗漏的未加锁的容器访问操作
  • 互斥锁的作用域是否正确,是否出现提前解锁、重复加锁的问题

内容的提问来源于stack exchange,提问作者GildedTruth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 00:06:00