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

多线程合并4个文本文件字符串异常:仅3个文件成功合并

多线程合并文件内容丢失问题排查

问题描述

读取4个含字符串的文本文件,通过单线程与多线程方式合并为单个string vector后排序并对比速度。单线程逻辑与排序算法运行正常,但多线程场景下仅3个文件的内容被合并到vector中,包含最多字符串的第4个文件内容丢失。

相关代码

多线程处理函数

void MultiThreaded(vector<string> filefist, ESort sort) {
    vector<string> stringlist;
    vector<thread> workerThreads(filelist.size());
    for (unsigned int i = 0; i < filelist.size() ; ++i) {
        workerThreads[i] = thread(FileRead, filelist[i],&stringlist);
    }

    for (unsigned int i = 0; i < filelist.size(); i++){
        workerThreads[i].join();
    }

    stringlist = Sort(stringlist, sort);
}

文件读取函数

void FileRead(string fname, vector<string>* outlist) {
    *outlist = ReadFile(fname);
}

注:排序代码为单多线程共用。

问题根源

  1. 赋值操作导致内容覆盖
    每个线程调用FileRead时,通过*outlist = ReadFile(fname)将当前文件内容直接赋值给目标vector,这会完全替换vector原有内容,而非追加。多线程并发执行该操作时,会互相覆盖结果,最终stringlist仅保留最后完成的线程读取的内容。你观察到的"3个文件内容被合并"是线程竞争导致的随机结果,本质是赋值操作的冲突覆盖。

  2. vector非线程安全容器
    即使改为追加操作(如push_back/insert),直接在多线程中修改同一个vector也会触发数据竞争——vector的内部扩容、指针移动等操作在并发场景下会出现未定义行为,可能导致数据丢失、程序崩溃。

修复方案

方案1:独立读取后合并(推荐,无锁开销)

让每个线程独立读取文件内容到专属vector,主线程等待所有线程完成后再合并结果,彻底避免线程竞争:

// 修改文件读取函数,返回独立的结果vector
vector<string> FileRead(string fname) {
    return ReadFile(fname);
}

void MultiThreaded(vector<string> filelist, ESort sort) {
    vector<vector<string>> threadResults(filelist.size());
    vector<thread> workerThreads;

    for (unsigned int i = 0; i < filelist.size(); ++i) {
        workerThreads.emplace_back([i, &filelist, &threadResults]() {
            threadResults[i] = FileRead(filelist[i]);
        });
    }

    // 等待所有线程执行完毕
    for (auto& t : workerThreads) {
        t.join();
    }

    // 合并所有线程的结果
    vector<string> stringlist;
    for (auto& result : threadResults) {
        stringlist.insert(stringlist.end(), result.begin(), result.end());
    }

    stringlist = Sort(stringlist, sort);
}

方案2:互斥锁保护追加操作(适合实时合并场景)

如果需要在线程中直接追加内容到总vector,需用互斥锁保护修改操作,避免数据竞争:

#include <mutex>

std::mutex vecMutex;

void FileRead(string fname, vector<string>* outlist) {
    vector<string> tempContent = ReadFile(fname);
    // 加锁后安全追加内容
    std::lock_guard<std::mutex> lock(vecMutex);
    outlist->insert(outlist->end(), tempContent.begin(), tempContent.end());
}

void MultiThreaded(vector<string> filelist, ESort sort) {
    vector<string> stringlist;
    vector<thread> workerThreads(filelist.size());
    for (unsigned int i = 0; i < filelist.size() ; ++i) {
        workerThreads[i] = thread(FileRead, filelist[i],&stringlist);
    }

    for (unsigned int i = 0; i < filelist.size(); i++){
        workerThreads[i].join();
    }

    stringlist = Sort(stringlist, sort);
}

说明

方案1的性能更优,因为线程间无锁竞争,仅在主线程执行一次合并操作;方案2适合需要实时合并内容的场景,但锁会带来一定性能损耗,文件内容越多损耗越明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:27:18