如何在 C++ 中创建竞争条件
How to create a race condition in C++
我想测试一些对象在竞争条件下的线程安全功能。为了对此进行测试,我想从两个(或更多)不同的线程同时调用一个函数。我如何编写代码来保证函数调用将同时发生或至少足够接近以产生预期的效果?
您能做的最好的事情就是用力敲打代码并检查所有可能出现问题的小迹象。如果存在竞争条件,您应该能够编写最终会触发它的代码。考虑:
#include <thread>
#include <assert.h>
int x = 0;
void foo()
{
while (true)
{
x = x + 1;
x = x - 1;
assert(x == 0);
}
}
int main()
{
std::thread t(foo);
std::thread t2(foo);
t.join();
t2.join();
}
无论我在哪里测试它,它都能很快断言。然后我可以添加关键部分,直到断言消失。
但事实上,不能保证它会断言。但是我已经在大规模生产代码中反复使用了这种技术。可以肯定的是,您可能只需要长时间敲打您的代码。
有一个结构,其字段为零整数数组,长度可能为 300-500 kB。然后从两个线程复制另外两个结构(一个有 1s 另一个有 2s),就在一些原子内存发出障碍之前(通过检查原子变量的值从主线程确保未定义的行为区域已经完成)。
这应该很有可能出现未定义的行为,也许您可以在其中看到混合的 1、2(甚至 0?)就知道它发生了。
但是,当您删除所有控制内容(例如原子)时,新形状也可能是另一种未定义的行为并且表现不同。
一个很好的方法是插入适时的 sleep
调用。例如,您可以使用它来强制按您要测试的顺序组合事件(线程 1 执行某些操作,然后线程 2 执行某些操作,然后线程 1 执行其他操作)。缺点是您必须知道将 sleep
调用放在哪里。稍微这样做之后,您应该开始有感觉了,但是一些良好的直觉在开始时会有所帮助。
如果您可以获得线程 ID 的句柄,您也许可以有条件地调用 sleep
或从特定线程命中断点。
此外,我很确定 Visual Studio 和(我认为)GDB 允许您冻结某些线程 and/or 运行 特定线程。
我想测试一些对象在竞争条件下的线程安全功能。为了对此进行测试,我想从两个(或更多)不同的线程同时调用一个函数。我如何编写代码来保证函数调用将同时发生或至少足够接近以产生预期的效果?
您能做的最好的事情就是用力敲打代码并检查所有可能出现问题的小迹象。如果存在竞争条件,您应该能够编写最终会触发它的代码。考虑:
#include <thread>
#include <assert.h>
int x = 0;
void foo()
{
while (true)
{
x = x + 1;
x = x - 1;
assert(x == 0);
}
}
int main()
{
std::thread t(foo);
std::thread t2(foo);
t.join();
t2.join();
}
无论我在哪里测试它,它都能很快断言。然后我可以添加关键部分,直到断言消失。
但事实上,不能保证它会断言。但是我已经在大规模生产代码中反复使用了这种技术。可以肯定的是,您可能只需要长时间敲打您的代码。
有一个结构,其字段为零整数数组,长度可能为 300-500 kB。然后从两个线程复制另外两个结构(一个有 1s 另一个有 2s),就在一些原子内存发出障碍之前(通过检查原子变量的值从主线程确保未定义的行为区域已经完成)。
这应该很有可能出现未定义的行为,也许您可以在其中看到混合的 1、2(甚至 0?)就知道它发生了。
但是,当您删除所有控制内容(例如原子)时,新形状也可能是另一种未定义的行为并且表现不同。
一个很好的方法是插入适时的 sleep
调用。例如,您可以使用它来强制按您要测试的顺序组合事件(线程 1 执行某些操作,然后线程 2 执行某些操作,然后线程 1 执行其他操作)。缺点是您必须知道将 sleep
调用放在哪里。稍微这样做之后,您应该开始有感觉了,但是一些良好的直觉在开始时会有所帮助。
如果您可以获得线程 ID 的句柄,您也许可以有条件地调用 sleep
或从特定线程命中断点。
此外,我很确定 Visual Studio 和(我认为)GDB 允许您冻结某些线程 and/or 运行 特定线程。