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

Valgrind下C++回测程序移除cout后死锁冻结问题求助

问题分析与解决方案

核心问题根源

  1. 内存可见性缺失:全局变量done是普通bool类型,未做同步处理。后台线程修改done = true后,main线程可能因CPU缓存优化无法感知到该更新,导致循环无法正常退出。
  2. 忙等引发线程饥饿:移除cout语句后,main线程进入无延迟的忙等循环,在Valgrind的调度环境下,后台线程难以获得CPU时间片执行数据初始化任务,无法填充data_frames或更新done状态,最终表现为程序冻结。而cout的IO操作会引入天然延迟,让main线程暂停,给后台线程留出执行窗口。

具体修复步骤

1. 修复内存可见性问题

将done改为原子类型,确保跨线程的状态更新可见:
在dataparser.cpp中:

  • 添加头文件<atomic>
  • 将bool done = false;替换为std::atomic<bool> done = false;

2. 避免忙等,给后台线程执行机会

在main函数的循环中,当没有数据可读取时,让出CPU资源:
修改main.cpp的while循环:

while (1) {
    auto tmp = getNextKLine();
    if (tmp.has_value())
        cout << idx++ << ": " << tmp.value().open_time << '\n';
    else if (isDone())
        break;
    std::this_thread::yield(); // 让出CPU,允许后台线程执行
}

或者使用短时间睡眠(更稳妥):

#include <chrono> // 需要添加这个头文件
// ...
while (1) {
    auto tmp = getNextKLine();
    if (tmp.has_value())
        cout << idx++ << ": " << tmp.value().open_time << '\n';
    else if (isDone())
        break;
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
}

3. 修复数据读取逻辑(可选但必要)

readTradesBetweenTime函数中有一条提前return ts;语句,导致后续的交易数据读取逻辑完全未执行,会导致AggTrade的trades字段始终为空。需要注释或删除这条不必要的return:

std::vector<Trade> readTradesBetweenTime(int64_t first_id, int64_t last_id) {
    static std::vector<Trade> trade_buffer;
    std::vector<Trade> ts;
    // return ts; // 删除或注释此行
    // ... 后续逻辑保留
}

额外优化建议

  • 避免使用detach()管理后台线程,改用join()更安全,确保main线程等待后台线程完成后再退出。修改initParser函数:
void initParser(FILE *kl, FILE *t, FILE *a) {
    k = kl, tr = t, at = a;
    std::thread thr(readKLine);
    // thr.detach();
    thr.join(); // 改为join,等待数据初始化完成后再返回
}

如果需要异步加载数据,可使用条件变量替代忙等,实现更高效的线程同步。

内容的提问来源于stack exchange,提问作者Le Xuan Ky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:13:15