views:

700

answers:

4

I want to increment an unsigned integer from multiple threads.

I know about Interlocked.Increment, but it does not handle unsigned integers. I could use lock(), but I would rather not if possible for performance reasons.

Is it thread safe just to increment it in the normal way? It would not matter if the occasional increment got lost, as it's only used for statistics. What I don't want is the value to get corrupted.

+2  A: 

you can declare the uint as volatile.

http://msdn.microsoft.com/en-us/library/x13ttww7(VS.71).aspx

Sesh
That only makes sure that any changes to the variable are written back to memory immediately, instead of waiting until either the thread yields or the value is displaced in a register. It does not protect access to the field, i.e. two (or more) threads may read the same value, increment once, and write back, effectively increasing the value by 1.
Cecil Has a Name
Please read the requirements above and also the example athttp://msdn.microsoft.com/en-us/library/7a2f3ay4.aspx.For the given case it is sufficient.
Sesh
How performant is volatile compared to Interlocked.Increment? Same? Better?
jrista
+5  A: 

If you really need the full range of an unsigned int (2^32 - 1) rather a signed int (2^31 -1), you could cast to an int64 (there is an Interlocked.Increment overload that takes int64) and then cast back to an unsigned int.

Mitch Wheat
That would be my choice too.
ChrisBD
Note though that Interlocked.Increment(ref long) is only actually atomic under a 64-bit OS (see documentation)
jerryjvl
Personally I'd make do with the regular int for general safety... if 31 bits is not enough, then I doubt 32 will actually work much better, unless the problem is specifically restricted exactly between 2G and 4G measurements.
jerryjvl
@Jerryjvl - Reminds me of the days of 16bit calculations in 8bit systems.
ChrisBD
A: 

From what I know you should use a Mutex

http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx

pixel3cs
A mutex is far heavier than a CLR monitor, as well as not having as good language support.
Jon Skeet
+8  A: 

You say you don't want to use lock for performance reasons - but have you tested it? An uncontested lock (which this is likely to be, by the sounds of it) is pretty cheap.

I generally go for "obviously correct" rather than "clever and possibly better performing" when it comes to threading (and in general, but especially for threading).

Benchmark your app with and without locking, and see whether you can even notice the difference. If locking makes a significant difference then sure, use cunning stuff. Otherwise, I'd just stick with a lock.

One thing you might want to do is use Interlocked.Increment with an int and just cast it when necessary to get a uint, like this:

using System;
using System.Reflection;
using System.Threading;

public class Test
{
    private static int count = int.MaxValue-1;

    public static uint IncrementCount()
    {
        int newValue = Interlocked.Increment(ref count);
        return (uint) newValue;
    }

    public static void Main()
    {
        Console.WriteLine(IncrementCount());
        Console.WriteLine(IncrementCount());
        Console.WriteLine(IncrementCount());
    }

}

Output:

2147483647
2147483648
2147483649

(In other words it wraps with no problems.)

Jon Skeet
I agree why complicate things unless performance actually becomes an issue. I can't imagine a lock for incrementing a single value is going to remain for very long or use much resources.
PeteT
+1 for the safe wrap-up!
Galilyou