一、Valgrind 的 TSan 替代方案
之前讲过 ThreadSanitizer 能检测数据竞争,但需要重编译。如果你有一个已经编译好的二进制(或者第三方库没源码),可以用 Helgrind 或 DRD 做运行时数据竞争检测。
# Helgrind(更详细,但更慢)
valgrind --tool=helgrind ./my_multithread_program
# DRD(更快一点,但可能漏报)
valgrind --tool=drd ./my_multithread_program
二、输出示例
#include <thread>
#include <iostream>
int counter = 0; // 没有锁保护
void worker() {
for (int i = 0; i < 100000; i++) {
counter++; // 数据竞争!
}
}
int main() {
std::thread t1(worker);
std::thread t2(worker);
t1.join();
t2.join();
std::cout << counter << std::endl;
return 0;
}
valgrind --tool=drd ./race
# 输出:
# DRD: data race on address 0x601050 in object 'counter'
# Conflicting store by thread 1 at 0x400B34: worker() race.cpp:6
# Conflicting load by thread 2 at 0x400B38: worker() race.cpp:6
# Allocation context: BSS section of /tmp/race
三、Helgrind vs DRD vs TSan
| 工具 | 是否需要重编译 | 运行速度 | 精确度 |
|---|---|---|---|
| TSan(-fsanitize=thread) | 需要 | 慢 5-10x | 高 |
| DRD(valgrind) | 不需要 | 慢 20-30x | 中 |
| Helgrind(valgrind) | 不需要 | 慢 20-30x | 高 |
实际选择:
如果你有源码:用 -fsanitize=thread(最快最准)
如果你只有二进制:用 DRD 或 Helgrind
Helgrind 的报错比 DRD 详细,但慢一点