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

VS2019中使用std::vector<std::future<T>>时程序崩溃原因咨询

多线程哈希处理触发abort崩溃的问题修复

我尝试用C++实现多线程哈希处理输入消息流,代码如下,但在Visual Studio 2019调试时,程序仅创建少量线程就从abort.h触发崩溃。

原代码片段:

std::vector<std::future<HashData>> futures;
std::vector<std::string> messages;

for (int i = 0; i < messages.size(); i++)
{
  std::promise<HashData> promiseHashData;
  std::future<HashData> futureHashData = promiseHashData.get_future();
  futures.emplace_back(std::move(futureHashData));
  std::async(std::launch::async, [&]() {PerformHash(std::move(promiseHashData), messages[i]);});
}

std::vector<HashData> vectorOfHashData;
// 等待所有异步任务完成
for (auto& futureObj : futures)
{
  vectorOfHashData.push_back(futureObj.get());
}
void PerformHash(std::promise<HashData>&& promObject, std::string& message)
{
    ComputeHashUsingSHA256(message);
    HashData data;

    // 为HashData对象赋值
    data.i = i;
    data.blocks = blocks;
    data.blocksize = blocksize;
    data.blockbufs = blockbufs;
    data.secs = secs;
    memcpy(data.digest, digest, SHA256_DIGEST_SIZE);

    data.has_hashdata = has_hashdata;
    memcpy(data.hashdata_buf, hashdata_buf, c_hashsize);

    promObject.set_value(data);
}

问题分析:

  • 栈变量引用捕获失效:循环中的promiseHashData是栈上局部变量,lambda用[&]捕获引用后,循环迭代会销毁旧promise并创建新的,异步任务执行时可能访问已销毁的promise,触发未定义行为导致崩溃。
  • 字符串引用捕获错误:messages[i]的引用在循环中会被后续迭代覆盖,异步任务可能访问到错误的字符串对象,甚至已失效的内存。
  • std::async返回值被丢弃:std::async返回的std::future如果被直接丢弃,会阻塞当前线程直到该异步任务完成,导致代码实际串行执行,还可能引发资源管理问题。
  • 未定义变量使用:PerformHash函数中的i、blocks、digest等变量未定义,会导致编译或运行时错误。

修复方案:

  1. 改用移动捕获promise:将promise移动到lambda中,避免引用失效;同时按值捕获messages[i],确保异步任务拿到独立的字符串副本。
  2. 保存std::async的返回值:避免异步任务被阻塞,同时管理任务生命周期。
  3. 修正PerformHash的参数和变量:将所需变量通过参数传递,或在函数内正确定义。

修复后的代码:

#include <vector>
#include <future>
#include <string>
#include <cstring>

// 假设HashData结构已定义
struct HashData {
    int i;
    int blocks;
    size_t blocksize;
    void* blockbufs;
    double secs;
    unsigned char digest[32]; // SHA256_DIGEST_SIZE
    bool has_hashdata;
    unsigned char hashdata_buf[64]; // 假设c_hashsize为64
};

// 修正哈希计算函数,直接填充HashData
void ComputeHashUsingSHA256(const std::string& message, HashData& data) {
    // 此处实现实际的SHA256哈希逻辑,以下为模拟示例
    data.blocks = 1;
    data.blocksize = message.size();
    data.secs = 0.001;
    std::memset(data.digest, 0x00, sizeof(data.digest));
    data.has_hashdata = true;
    std::memset(data.hashdata_buf, 0x01, sizeof(data.hashdata_buf));
}

void PerformHash(std::promise<HashData>&& promObject, std::string message, int index) {
    HashData data;
    data.i = index;
    ComputeHashUsingSHA256(message, data);
    
    promObject.set_value(data);
}

int main() {
    std::vector<std::string> messages = {"msg1", "msg2", "msg3"};
    std::vector<std::future<HashData>> futures;
    std::vector<std::future<void>> asyncFutures; // 保存async任务的future

    for (int i = 0; i < messages.size(); i++)
    {
        std::promise<HashData> promiseHashData;
        std::future<HashData> futureHashData = promiseHashData.get_future();
        futures.emplace_back(std::move(futureHashData));
        
        // 移动捕获promise,值捕获message和索引i
        asyncFutures.emplace_back(std::async(std::launch::async, 
            [promise = std::move(promiseHashData), msg = messages[i], idx = i]() mutable {
                PerformHash(std::move(promise), msg, idx);
            }));
    }

    std::vector<HashData> vectorOfHashData;
    // 等待所有哈希结果返回
    for (auto& futureObj : futures)
    {
        vectorOfHashData.push_back(futureObj.get());
    }

    return 0;
}

额外说明:

  • 用mutable修饰lambda,允许在lambda内移动捕获的promise对象。
  • 调整ComputeHashUsingSHA256的参数,直接传入HashData引用填充结果,避免函数内使用未定义变量。
  • 保存std::async返回的std::future<void>,确保异步任务能正常执行完毕,不会被提前阻塞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:55:38