Interlocked.Increment() not working the way I'd expect in the Task Parallel Library
I have a Parallel.ForEach() loop that takes a list of开发者_如何学Go URL's and downloads each of them for some additional processing. Outside my loop I have declared a loop counter variable and inside the loop body I use Interlocked.Increment() thinking this would be the best way to keep a "thread safe" way of increasing the count as each loop interation is performed.
int counter = 0;
Parallel.ForEach(urlList, (url, state) =>
{
// various code statments
Interlocked.Increment( ref counter );
Debug.WriteLine(" ......... counter: " + counter);
});
I would have thought that I would see something similar to:
......... 1
......... 2
......... 3
......... 4
......... 5
.........
.........
......... n
But what I get instead is 16 " ......... 0" (this is because I have a dual quad core computer with 8 native cores, but hyper threading is enabled giving me a total of 16 cores). Then I will start to see the counter get incremented normally for the most part but sometimes I will see duplicate or even triplicate counter values in the Debug output.
Using a Parallel.ForEach() what is the best way to count loop iterations? Thanks for any advice.
Interlocked.Increment
will return your incremented value.
So,
int counter = 0;
Parallel.ForEach(urlList, (url, state) =>
{
// various code statments
var counterNow = Interlocked.Increment( ref counter );
Debug.WriteLine(" ......... counter: " + counterNow);
});
should return the counter value as it was incremented.
When you are running on a multi processor/multi-core machines and have multiple application threads, you need to be aware that the values you see for variables may not reflect the actual current state of that variable. This is because there may be many individual caches, for each CPU or die or socket, and your thread can read the cached value (saving a hit to read main memory)
If you just want to read a value that is updated by multiple threads, you should use Interlocked.Read()
to guarantee you have the current value for counter
.
This is because the Increment + WriteLine together are not atomic.
It might be that thread1 increments counter
, then thread2 increments it again, and then the two threads get to the WriteLine part with the same value of counter
.
I'm not sure, but I think this is probably due to the way variable captures work in lambdas. Have you tried putting it in a separate function, or moving the variable outside and declaring it as static?
精彩评论