我写了一些线程代码,这似乎是一个错误的假设,即整数是线程安全的。现在看来,尽管它们是线程安全的,但我使用它们并不是线程安全的。我使用一个全局整数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?
谢谢你看一看。
发布于 2013-06-19 14:03:54
如果多线程在没有保护的情况下修改变量,那么是的,您将面临数据竞争。如果两个线程试图在同一实例中递增或递减,则会发生以下情况:
该读取/修改/写入不是原子的。如果有两个线程同时执行,那么就会出现规范的数据竞争。
变量不是递增两次,而是只递增一次。
在这种情况下,不需要完整的临界区。使用InterlockedIncrement
执行无锁、线程安全的修改。
https://stackoverflow.com/questions/17193150
复制相似问题