问题
I'm creating new threads for every sql call for a project. There are millions of sql calls so I'm calling a procedure in a new thread to handle the sql calls.
In doing so, I wanted to increment and decrement a counter so that I know when these threads have completed the sql query.
To my amazement the output shows NEGATIVE values in the counter. HOW? When I am starting with 0 and adding 1 at the beginning of the process and subtracting 1 at the end of the process?
This int is not called anywhere else in the program.. the following is the code..
public static int counter=0;
while(!txtstream.EndOfStream)
{
new Thread(delegate()
{
processline();
}).Start();
Console.WriteLine(counter);
}
public static void processline()
{
counter++;
sql.ExecuteNonQuery();
counter--;
}
Output looks something like this:
1
21
-2
-2
5
回答1:
Nothing mysterious about it, you are using threading, right?
The ++
and --
operator aren't thread safe. Do this.
public static void processline()
{
Interlocked.Increment(ref counter);
sql.ExecuteNonQuery();
Interlocked.Decrement(ref counter);
}
回答2:
How to overcome
Use Interlocked.Increment
and Interlocked.Decrement
to safely change the value of the counter.
Why this happens
You have counter as variable, which is shared across multiple threads. This variable is non-volatile and not wrapped by any synchronization block, so each thread has its own copy of that variable. So if two threads try to change it value at the same time, value would be overrriden by copy from thread which accessed it last.Imagine you start your code in two different threads:
- Initially counter equals zero, both threads havy copy of that
- Both thread invoke increment their cached copies, and than change counter. So thread1 increments its copy to 1 and overrides counter, thread2 also increments its copy (still equal to zero) to 1 and overrides counter to, again, 1. After that that value is propagated to all threads (all copies are refreshed)
- Both threads invoke sql query. Due to variability in sql performance, these queries are completed in different time.
- Thread1 ends sql query, decrements counter from 1 to 0. Counter value is propagated to all threads
- After some time, Thread2 ends sql query, decrement counter from already propagated 0 to -1. Counter value is propagated to all threads. And it is -1.
来源:https://stackoverflow.com/questions/27322145/mysterious-negative-counter-value