0

I am trying to generate unique integer Ids that can be used from multiple threads.

public partial class Form1 : Form
{
    private static int sharedInteger;
    ...

private static int ModifySharedIntegerSingleTime()
{
    int unique = Interlocked.Increment(ref sharedInteger);

    return unique;
}

SimulateBackTestRow1()
{
    while (true)
    {
        int num = ModifySharedIntegerSingleTime();
    }
}
SimulateBackTestRow2()
{
    while (true)
    {
        int num = ModifySharedIntegerSingleTime();
    }
}

Task modifyTaskOne = Task.Run(() => SimulateBackTestRow1());
Task modifyTaskTwo = Task.Run(() => SimulateBackTestRow2());

However, when code that takes a unique number that has not been used before gets passed a number that was acquired by ModifySharedIntegerSingleTime, I am getting collisions with numbers that are not unique.

What is the correct way to get unique int Ids in a thread-safe way?

Ivan
  • 7,448
  • 14
  • 69
  • 134

1 Answers1

4

You only have 2^32 unique values with an integer. Since you're generating values as quickly as you can in a loop, it wont take you long to generate more than the ~4 billion values you need to have run out and start returning values you've already used and causing collisions. Either you have some bug in your program that results in you generating more new values than you actually need, or you need to use a type that has more values, such as a long or GUID.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • It is even worse given that integer splits roughly into positive and negative numbers, and the algo starts at 0, so you literally only have half the number space before getting... an error? What is the behavior for Interlocked.Increment when an overrun occurs? – TomTom Sep 09 '21 at 16:48
  • LOL!. Yeah I also forgot that Sleep(1) doesn't mean, one second :-) – Ivan Sep 09 '21 at 16:49
  • 1
    @TomTom It doesn't error, it just overflows. So where it starts doesn't matter (when using it as strictly an identifier) because it always takes exactly 2^32 invocations before it reaches the starting place. – Servy Sep 09 '21 at 16:53
  • @Ivan I strongly recommend never passing an integer to sleep ever. Always use a timespan, then you don't make mistakes like that. Do the same anywhere else you keep track of timespans and don't use integers in their place as the unit is often ambiguous. – Servy Sep 09 '21 at 16:54