我用一些似乎不正确的假设编写了一些线程代码,整数是线程安全的。现在似乎虽然它们是,但我对它们的使用并不是线程安全的。我使用全局整数ThreadCount来保存线程数。在线程创建期间,我增加ThreadCount。在线程销毁期间,我减少它。在创建所有线程之后,我等待它们完成(ThreadCount应该降为0),然后编写我的最终报告并退出。
有时候(5%),我永远不会达到0,即使对我的日志进行验尸检查表明所有线程都已运行并完成。因此所有迹象都表明ThreadCount遭到践踏。我一直在告诉自己,这是不可能的,因为它是一个整数,我只是使用inc / dec。
这里有一些相关的代码:
var // global
ThreadCount : integer; // Number of active threads
...
constructor TTiesUpsertThread.Create(const CmdStr : string);
begin
inherited create(false);
Self.FreeOnTerminate := true;
...
Inc(ThreadCount); // Number of threads created. Used for throttling.
end;
destructor TTiesUpsertThread.Destroy;
begin
inherited destroy;
Dec(ThreadCount); // When it reaches 0, the overall job is done.
end;
...
//down at the end of the main routine:
while (ThreadCount > 0) do // Sometimes this doesn't ever end.
begin
SpinWheels('.'); // sleeps for 1000ms and writes dots... to console
end;
我认为我的问题是inc / dec。我想我会在两个或多个dec()同时命中并且读取相同值的情况下发生碰撞,因此他们用相同的值替换它。例如:ThreadCount = 5,两个线程同时结束,两个读取5,替换为4.但新值应为3.
这在我们的测试环境中永远不会遇到麻烦(不同的硬件,拓扑,负载等等),所以在我尝试"出售&之前,我正在寻找确认这可能是问题的原因。 #34;这个业务部门的解决方案。
如果这是我的问题,我是否使用关键选择来保护inc / dec?
谢谢你看看。
答案 0 :(得分:7)
如果多个线程在没有保护的情况下修改变量,那么是的,您有一个数据争用。如果两个线程试图在同一个实例中递增或递减,那么会发生什么:
读取/修改/写入不是原子的。如果您有两个线程同时执行,那么您将进行规范数据竞争。
而不是变量递增两次,它只增加一次。
在这种情况下,不需要完整的关键部分。使用InterlockedIncrement
执行无锁,线程安全修改。