【问题标题】:Mysterious C++ threading crash神秘的 C++ 线程崩溃
【发布时间】:2020-11-10 16:22:53
【问题描述】:

以下代码在输入run 函数时奇怪地崩溃了。没有任何 printfs 触发,单步进入函数会导致崩溃。它是未定义的行为,还是编译器错误?我正在使用 Apple clang 12.0.0 编译 MacOS。它与EXC_BAD_ACCESS (code = 2) 一起崩溃。

#include <iostream>
#include <thread>
#include <vector>

struct Chunk {
    // the array must be this big
    // other array sizes don't trigger the bug consistently
    uint8_t array[524288];
};

std::thread generator_thread;
std::mutex generator_lock;
std::vector<Chunk*> to_generate;
std::condition_variable data_ready;
std::atomic<bool> running;

void begin();
void run();

void begin() {
    running = true;
    auto func = [] {
        run();
    };
    generator_thread = std::thread(func);
}

void run() {
    printf("Running in generator\n");
    while (running) {
        printf("Running in loop\n");
        Chunk *task;

        // take a chunk from the queue
        {
            std::unique_lock<std::mutex> lock(generator_lock);
            data_ready.wait(lock, [] { return to_generate.size() > 0 || !running; });
            if (!running) break;

            task = to_generate.back();
            to_generate.pop_back();
        }

        printf("deref chunk\n");

        // Despite never being executed in this example, this line merely existing
        // will cause a crash when entering the run_generator function.
        Chunk chunk = *task;

        // *task.chunk;
        // ^^^ Only having the line above will not trigger the bug; it must be assigned
    }
}

int main(int argc, const char *argv[]) {
    begin();
    while (true) {
        printf("run\n");
    }
    return 0;
}

【问题讨论】:

  • "这个功能以前可以用,完全没动过,现在突然不行了。"可能是内存损坏。尝试使用 Valgrind 之类的程序。还要检查线程中可能的竞争条件和其他未定义的行为。
  • @LHLaurini 我用线程清理器和地址清理器运行,没有内存损坏。我可能会尝试 valgrind 并在此处更新。

标签: c++ multithreading macos pthreads


【解决方案1】:

所以,当您将函数更改为为半兆字节对象预留空间的堆栈帧时...在设置该堆栈帧时,它会在函数开始时崩溃?

这可能是因为您使sizeof Chunk 等于整个默认 OSX 线程堆栈大小 512Kb。如果你单步进入函数,你应该能够看到触发故障的指令,它很可能是堆栈帧设置/函数前导的一部分。

所有这些都是特定于实现的(堆栈帧、每个线程的堆栈大小),但是将非常大的东西放在堆栈上通常是个坏主意。

【讨论】:

  • 哇,我简直不敢相信我忘记了这一点。我非常专注于使线程工作,我想我有隧道视野。