Do blocking of global iterator make sense?

I need to do some stuff what request reading of each elements of arrey in threads. Each thread just need read element [i] and do i++. Do i need to lock i++?

I read somewhere that asynchronous operacions with double variables need locking to prevent unecxpected results. How can i tell the same about another operations? Here is any list of problematic operations?

For more specifics. I have global variables:

public static int[] IntArray;
public static int ArrayPointer = 0;

I start some threads in pool this way:

ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod));

Like this:

static void ThreadMethod() {
  //loop until ArrayPointer is too big
  Console.WriteLine(IntArray[ArrayPointer]);
  ArrayPointer++;
  //end of loop
}
Jon Skeet
people
quotationmark

The important point here is that you have a shared variable, and the ++ operator does a read/modify/write operation. That operation is not atomic, even though each individual part of it is.

So you could easily have:

Thread 1                 Thread 2

Read ArrayPointer (0)   
                         Read ArrayPointer(0)
Increment locally (1)
                         Increment locally (1)
Write ArrayPointer (1)
                         Write ArrayPointer (1)

So despite there being two increments, you've got a result of 1.

You can use Interlocked.Increment to increment atomically, but you'd still want to use the result of that increment operation for the rest of the iteration of the loop, rather than reading the variable multiple times.

I would actually suggest three things here:

  • Don't use static variables for this. Global state makes code hard to test and hard to reason about
  • Isolate the threading aspect from anything else - encapsulate it in a class exhibiting higher-level behaviour. If you really, really need global state, you can then have a static readonly variable of that class type, if you want.
  • Try not to do too much low-level stuff yourself at all. .NET has a huge range of options for concurrent programming, whether that's the "core" TPL (with language support in the form of async/await) or something like TPL Dataflow built on top of it. These are building blocks which have been written by people whose primary job is to make this sort of thing rock solid and performant. Don't try to do their work yourself :)

people

See more on this question at Stackoverflow