神秘的负面价值

我正在为项目的每个sql调用创建新线程。 有数百万的sql调用所以我在一个新线程中调用一个过程来处理sql调用。

这样做,我想增加和减少一个计数器,以便我知道这些线程何时完成了sql查询。

令我惊讶的是,输出显示了计数器中的负值。 怎么样? 当我从0开始并在流程开始时加1并在流程结束时减去1?

这个int不会在程序中的任何其他位置调用..以下是代码..

public static int counter=0; while(!txtstream.EndOfStream) { new Thread(delegate() { processline(); }).Start(); Console.WriteLine(counter); } public static void processline() { counter++; sql.ExecuteNonQuery(); counter--; } 

输出看起来像这样:

 1 21 -2 -2 5 

没有什么神秘的,你正在使用线程,对吧?

++--运算符不是线程安全的。 做这个。

 public static void processline() { Interlocked.Increment(ref counter); sql.ExecuteNonQuery(); Interlocked.Decrement(ref counter); } 

如何克服

使用Interlocked.IncrementInterlocked.Decrement安全地更改计数器的值。

为什么会这样

您有计数器作为变量,它在多个线程之间共享。 此变量是非易失性的,不会被任何同步块包装,因此每个线程都有自己的变量副本。 因此,如果两个线程同时尝试更改它的值,则值将被最后访问它的线程的副本覆盖。
想象一下,你在两个不同的线程中启动你的代码:

  1. 最初的计数器等于零,两个线程都是havy副本
  2. 线程调用都会增加缓存副本,而不是更改计数器。 因此,thread1将其副本递增为1并覆盖计数器,thread2也将其副本(仍然等于零)递增为1并再次重写计数器1.之后,该值将传播到所有线程(所有副本都刷新)
  3. 两个线程都调用sql查询。 由于sql性能的可变性,这些查询在不同的时间完成。
  4. Thread1结束sql查询,将计数器从1递减到0.计数器值传播到所有线程
  5. 经过一段时间后,Thread2结束sql查询,将已经传播的0减去计数器-1。 计数器值传播到所有线程。 它是-1。