我写了一些线程代码,似乎是一个不正确的假设,即整数是线程安全的。现在看来,尽管它们是,但我对它们的使用不是线程安全的。我使用全局整数 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。
这在我们的测试环境中永远不会遇到麻烦(不同的硬件、拓扑、负载等),所以在我尝试将这个解决方案“推销”给业务部门之前,我正在寻找这可能是问题的确认。
如果这是我的问题,我是否使用关键选择来保护 inc/dec?
谢谢参观。