0

Possible Duplicate:
ID generator with local static variable - thread-safe?

Would the following function return a unique number every time it is called? What about in a multi-threaded scenario?

int returnUniqueNumber()
{
  static int i = 0;
  ++i;
  return i;
}
Community
  • 1
  • 1

3 Answers3

5

It depends on your platform as to ehwther you'll get multithreading issues. On windows you'd be best off doing the following:

int returnUniqueNumber()
{
  volatile static long l = 0;
  return (int)InterlockedIncrement( &l );
}

The Interlocked* functions are guaranteed atomic.

Goz
  • 61,365
  • 24
  • 124
  • 204
  • You should not cast the `static int *` to a `volatile long *`--rather, it should be a (appropriately qualified) `LONG *` in both cases, and cast to an `int` on return (or just implicitly by the function.) `long` and `int` (and Windows' `LONG` typedef) are not always the same size, and while this cast may be fine on Windows, it encourages bad habits. :) – Jonathan Grynspan Nov 21 '10 at 13:11
  • @Jonathan: Point taken, Fixed. – Goz Nov 21 '10 at 13:12
  • I salute you, sir. +1 for you and +1 for simple accurate code! – Jonathan Grynspan Nov 21 '10 at 13:13
  • 1
    After the int's maximum value is reached and then to -ve values, doesn't it rotate back to 0, 1, 2 ... ? – riderchap Nov 21 '10 at 13:22
  • @riderchap: yes. It will count up to 2^31 - 1 and then it will swap to -2^31 and count up to 0. The loop continues ad infinitum. This is the main bonus of twos complement encoding ... – Goz Nov 21 '10 at 13:28
3

If your application were single-threaded, the code you posted would be in fact the correct, standards-compliant C/C++ way of generating unique numbers. However, since you're looking for a thread-safe solution, you must dive into platform-specific solutions. Goz has a good Windows solution. An equivalent on Mac OS X or iOS would be:

int returnUniqueNumber_APPLE(void) {
    static volatile int32_t i = 0;
    return (int)OSAtomicIncrement32Barrier(&i);
}

On any system where you compile with a recent-ish GCC, you also have GCC's intrinsics:

int returnUniqueNumber_GCC(void) {
    static volatile int i = 0;
    return __sync_add_and_fetch(&i, 1);
}
Jonathan Grynspan
  • 43,286
  • 8
  • 74
  • 104
  • Looks like we've covered Windows, Linux & MacOS :) – Moo-Juice Nov 21 '10 at 13:21
  • Not just Linux, but most *NIXes. :) In fact, we've got pretty much every major modern system covered. Android might be the only one left, and there you can just throw a `synchronized` keyword before the function's return type and be done. (Does Java have proper atomic operations? And I don't mean `AtomicInteger` etc.) – Jonathan Grynspan Nov 21 '10 at 13:23
1

Following on from Goz's answer regarding windows, for Linux/GCC see this question/answer:

Equivalent of InterlockedIncrement in Linux/gcc

in which case you'll want __sync_add_and_fetch()

Community
  • 1
  • 1
Moo-Juice
  • 38,257
  • 10
  • 78
  • 128