Thread safe id generation with Interlocked in c# - c#

I am trying to understand Interlocked in C# in thread synchronization.
public int MethodUsedByMultipleThreads()
{
var id = CreateNextId();
return id;
}
private long CreateNextId()
{
long id = 0;
Interlocked.Exchange(ref id , this._nextId);
Interlocked.Increment(ref this._nextId);
return id;
}
Is the line
Interlocked.Exchange(ref id , this._nextId);
redundant if I directly use
Interlocked.Increment(ref this._nextId);
return _nextId;
Will it serve the same purpose?

The line
Interlocked.Exchange(ref id, this._nextId);
is both redundant and incorrect. It is redundant because it is practically the same as:
id = this._nextId
...because the id is a local variable that is not shared with other threads. And it is incorrect because there is a race condition between incrementing the _nextId field and returning it from the method CreateNextId(). The correct implementation is:
private long CreateNextId()
{
long id;
id = Interlocked.Increment(ref this._nextId) - 1;
return id;
}
...or simply:
private long CreateNextId() => Interlocked.Increment(ref this._nextId) - 1;
The method Interlocked.Increment increments the _nextId field, and returns the incremented value as an atomic operation.
The subtraction - 1 is there to preserve the semantics of your existing code, regarding the meaning of the field _nextId. It might be preferable to change its name to _lastId or _idSeed, so that the - 1 can be removed.

long CreateNextId() => Interlocked.Increment(ref this._nextId);
This is all you need to generate sequential IDs in a thread-safe manner.
Do not use _nextId directly in any way: return _nextId is a mistake and will yield unpredictable results in a multithreaded environment - the value might be incremented by other threads after your call to Increment in the current thread.

Related

Can Interlocked CompareExchange be used correctly in this multithreaded round-robin implementation?

I need to round-robin some calls between N different connections because of some rate limits in a multithreaded context. I've decided to implement this functionality using a list and a "counter," which is supposed to "jump by one" between instances on each call.
I'll illustrate this concept with a minimal example (using a class called A to stand in for the connections)
class A
{
public A()
{
var newIndex = Interlocked.Increment(ref index);
ID = newIndex.ToString();
}
private static int index;
public string ID;
}
static int crt = 0;
static List<A> Items = Enumerable.Range(1, 15).Select(i => new A()).ToList();
static int itemsCount = Items.Count;
static A GetInstance()
{
var newIndex = Interlocked.Increment(ref crt);
var instance = Items[newIndex % itemsCount];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
static void Test()
{
var sw = Stopwatch.StartNew();
var tasks = Enumerable.Range(1, 1000000).Select(i => Task.Run(GetInstance)).ToArray();
Task.WaitAll(tasks);
}
This works as expected in that it ensures that calls are round-robin-ed between the connections. I will probably stick to this implementation in the "real" code (with a long instead of an int for the counter)
However, even if it is unlikely to reach int.MaxValue in my use case, I wondered if there is a way to "safely overflow" the counter.
I know that "%" in C# is "Remainder" rather than "Modulus," which would mean that some ?: gymnastics would be required to always return positives, which I want to avoid.
So what I wanted to cume up with is instead something like:
static A GetInstance()
{
var newIndex = Interlocked.Increment(ref crt);
Interlocked.CompareExchange(ref crt, 0, itemsCount); //?? the return value is the original value, how to know if it succeeded
var instance = Items[newIndex];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
What I am expecting is that Interlocked.CompareExchange(ref crt, 0, itemsCount) would be "won" by only one thread, setting the counter back to 0 once it reaches the number of connections available. However, I don't know how to use this in this context.
Can CompareExchange or another mechanism in Interlocked be used here?
You could probably:
static int crt = -1;
static readonly IReadOnlyList<A> Items = Enumerable.Range(1, 15).Select(i => new A()).ToList();
static readonly int itemsCount = Items.Count;
static readonly int maxItemCount = itemsCount * 100;
static A GetInstance()
{
int newIndex;
while (true)
{
newIndex = Interlocked.Increment(ref crt);
if (newIndex >= itemsCount)
{
while (newIndex >= itemsCount && Interlocked.CompareExchange(ref crt, -1, newIndex) != newIndex)
{
// There is an implicit memory barrier caused by the Interlockd.CompareExchange around the
// next line
// See for example https://afana.me/archive/2015/07/10/memory-barriers-in-dot-net.aspx/
// A full memory barrier is the strongest and interesting one. At least all of the following generate a full memory barrier implicitly:
// Interlocked class mehods
newIndex = crt;
}
continue;
}
break;
}
var instance = Items[newIndex % itemsCount];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
But I have to say the truth... I'm not sure if it is correct (it should be), and explaining it is hard, and if anyone touches it in any way it will break.
The basic idea is to have a "low" ceiling for crt (we don't want to overflow, it would break everything... so we want to keep veeeeeery far from int.MaxValue, or you could use uint).
The maximum possible value is:
maxItemCount = (int.MaxValue - MaximumNumberOfThreads) / itemsCount * itemsCount;
The / itemsCount * itemsCount is because we want the rounds to be equally distributed. In the example I give I use a probably much lower number (itemsCount * 100) because lowering this ceiling will only cause the reset more often, but the reset isn't so much slow that it is truly important (it depends on what you are doing on the threads. If they are very small threads that only use cpu then the reset is slow, but if not then it isn't).
Then when we overflow this ceiling we try to move it back to -1 (our starting point). We know that at the same time other bad bad threads could Interlocked.Increment it and create a race on this reset. Thanks to the Interlocked.CompareExchange only one thread can successfully reset the counter, but the other racing threads will immediately see this and break from their attempts.
Mmmh... The if can be rewritten as:
if (newIndex >= itemsCount)
{
int newIndex2;
while (newIndex >= itemsCount && (newIndex2 = Interlocked.CompareExchange(ref crt, 0, newIndex)) != newIndex)
{
// If the Interlocked.CompareExchange is successfull, the while will end and so we won't be here,
// if it fails, newIndex2 is the current value of crt
newIndex = newIndex2;
}
continue;
}
No, the Interlocked class offers no mechanism that would allow you to restore an Int32 value back to zero in case it overflows. The reason is that it is possible for two threads to invoke concurrently the var newIndex = Interlocked.Increment(ref crt); statement, in which case both with overflow the counter, and then none will succeed in updating the value back to zero. This functionality is just beyond the capabilities of the Interlocked class. To make such complex operations atomic you'll need to use some other synchronization mechanism, like a lock.
Update: xanatos's answer proves that the above statement is wrong. It is also proven wrong by the answers of this 9-year old question. Below are two implementation of an InterlockedIncrementRoundRobin method. The first is a simplified version of this answer, by Alex Sorokoletov:
public static int InterlockedRoundRobinIncrement(ref int location, int modulo)
{
// Arguments validation omitted (the modulo should be a positive number)
uint current = unchecked((uint)Interlocked.Increment(ref location));
return (int)(current % modulo);
}
This implementation is very efficient, but it has the drawback that the backing int value is not directly usable, since it circles through the whole range of the Int32 type (including negative values). The usable information comes by the return value of the method itself, which is guaranteed to be in the range [0..modulo]. If you want to read the current value without incrementing it, you would need another similar method that does the same int -> uint -> int conversion:
public static int InterlockedRoundRobinRead(ref int location, int modulo)
{
uint current = unchecked((uint)Volatile.Read(ref location));
return (int)(current % modulo);
}
It also has the drawback that once every 4,294,967,296 increments, and unless the modulo is a power of 2, it returns a 0 value prematurely, before having reached the modulo - 1 value. In other words the rollover logic is technically flawed. This may or may not be a big issue, depending on the application.
The second implementation is a modified version of xanatos's algorithm:
public static int InterlockedRoundRobinIncrement(ref int location, int modulo)
{
// Arguments validation omitted (the modulo should be a positive number)
while (true)
{
int current = Interlocked.Increment(ref location);
if (current >= 0 && current < modulo) return current;
// Overflow. Try to zero the number.
while (true)
{
int current2 = Interlocked.CompareExchange(ref location, 0, current);
if (current2 == current) return 0; // Success
current = current2;
if (current >= 0 && current < modulo)
{
break; // Another thread zeroed the number. Retry increment.
}
}
}
}
This is slightly less efficient (especially for small modulo values), because once in a while an Interlocked.Increment operation results to an out-of-range value, and the value is rejected and the operation repeated. It does have the advantage though that the backing int value remains in the [0..modulo] range, except for some very brief time spans, during some of this method's invocations.
An alternative to using CompareExchange would be to simply let the values overflow.
I have tested this and could not prove it wrong (so far), but of course that does not mean that it isn't.
//this incurs some cost, but "should" ensure that the int range
// is mapped to the unit range (int.MinValue is mapped to 0 in the uint range)
static ulong toPositive(int i) => (uint)1 + long.MaxValue + (uint)i;
static A GetInstance()
{
//this seems to overflow safely without unchecked
var newCounter = Interlocked.Increment(ref crt);
//convert the counter to a list index, that is map the unsigned value
//to a signed range and get the value modulus the itemCount value
var newIndex = (int)(toPositive(newCounter) % (ulong)itemsCount);
var instance = Items[newIndex];
//Console.WriteLine($"{DateTime.Now.Ticks}, Got instance: {instance.ID}");
return instance;
}
PS: Another part of the xy problem part of my question: At a friend's suggestion I am currently investigating using a LinkedList or something similar (with locks) to achieve the same purpose.

How to get next value when a common variable is increment in a parallel foreach?

I have a common variable that is updated inside a foreach, it is a counter, so I would like to get the next counter to be assigned inside a parallel foreach.
I have something like that:
int myCommonCounter = 5;
Parallel.Foreach(myList, (iterator, state) =>
{
if(iterator.MyProperty == X)
{
iterator.Position = miCommonCounter;
miCommonCounter = miCommonCunter + 1;
}
});
I want to avoid gaps in property iterator.Position and avoid duplicates too.
I have seen an example that does the sum of partial results, for example in this documentation, but it is not really the same case that I need.
So I would like to know if there are any away to update a counter to avoid gaps and duplicates when I updated inside the parallel foreach.
Thanks.
The overload of Parallel foreach that has 3 parameters for lambda argument has counter already.
You should use that instead of writing manual counter. It does not have duplicates. It wont have gaps either unless you stop loop for some reason.
Parallel.ForEach(source.Where(x => /*condition*/), (x, state, counter) =>
{
iterator.Position = (int) counter;
});
Note that counter is type of long so you have to cast it to int if Position is of int type

Is a property of type struct (TimeSpan) thread safe? [duplicate]

Is a C# struct thread-safe?
For example if there is a:
struct Data
{
int _number;
public int Number { get { return _number; } set { _number = value; } }
public Data(int number) { _number = number; }
}
in another type:
class DadData
{
public Data TheData { get; set; }
}
is property named TheData, thread-safe?
Well - best practice is that structs should always (except in a few very specific scenarios, and even then at risk) be immutable. And immutable data is always thread safe. So if you followed best practice and made this:
struct Data
{
readonly int _number;
public int Number { get { return _number; } }
public Data(int number) { _number = number; }
}
then yes; that is thread-safe. In all other cases the answer is "probably not".
Note also that atomicity rules apply, so even a single read or update to DadData.TheData cannot be assumed to be thread-safe, even with an immutable struct. You could (especially for oversized structs) have one thread reading the struct while another thread re-writes it; without synchronization bad things will happen (eventually).
No, structures in .NET are not intrinsically thread-safe.
However, the copy-by-value semantics that structures have great relevance to this converation.
If you are passing your structures around and assigning them in some way to variables or pass-by-value parameters (no ref or out keywords) then a copy is being used.
Of course, this means that any changes made to the copy are not reflected in the original structure, but it's something to be aware of when passing them around.
If you are accessing the structure directly in a manner that doesn't involve copy-by-value semantics (e.g. accessing a static field which is the type of the structure, and as Marc Gravel points out in his answer, there are many other ways) across multiple threads, then you have to take into account the thread-safety of the instance.
A struct is not any more thread-safe than an ordinary field or variable. If you have at least one thread modifying it, and at least one more thread touching it in any way at the same time, you may end up with unexpected/undefined behaviour.
Also, mutable structs are code smells. Is there some particular reason you need it to be a struct instead of a class? Do you need value-type semantics for this data?
Different threads' direct reads and writes of different members of a mutable struct will not interfere with each other. Different threads' access to the same member via Interlocked methods will behave according to the semantics of those methods. These facts may allow mutable structs to allow thread-safe behavior.
Mutable storage locations holding structs that offer no means of mutation except outright replacement offer no thread-safety whatsoever, except that in cases where a struct holds either a single 32-bit integer or a single object reference, an attempt to read a such a (single-item) struct storage location at the same time as it is being written is guaranteed to read entirely old data or entirely new data. Note that it is not possible to use any of the Interlocked methods with immutable structs--even structs which contain only a single integer or object reference.
No, they are not.
I created very simple app to see if 10/10 producer/consumer threads are accessing same struct variable. And eventually you will see Debugger.Break(); will be hit. Bank balance should never go under 0 value.
namespace StructThreadSafe
{
class Program
{
struct BankBalance
{
public decimal Balance { get; set; }
}
static void Main(string[] args)
{
BankBalance bankBalance = new BankBalance();
bankBalance.Balance = 100;
List<Task> allTasks = new List<Task>();
for (int q = 0; q < 10; q++)
{
Task producer = new Task(() =>
{
for (int i = 0; i < 1000; i++)
{
if (bankBalance.Balance < 0)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
bankBalance.Balance += 5;
Console.WriteLine("++Current Balance: " + bankBalance.Balance);
System.Threading.Thread.Sleep(100);
}
});
allTasks.Add(producer);
}
for (int w = 0; w < 10; w++)
{
Task consumer = new Task(() =>
{
for (int i = 0; i < 1000; i++)
{
if (bankBalance.Balance < 0)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
if (bankBalance.Balance > 15)
{
bankBalance.Balance -= 15;
Console.WriteLine("--Current Balance: " + bankBalance.Balance);
}
else
{
Console.WriteLine("**Current Balance below minimum: " + bankBalance.Balance);
}
System.Threading.Thread.Sleep(100);
}
});
allTasks.Add(consumer);
}
allTasks.ForEach(p => p.Start());
Task.WaitAll(allTasks.ToArray());
}
}
}
No. Why would it be thread-safe? It's just data. It doesn't become thread-safe by magic.

Should I use a different object to lock for each property?

I have a class and its properties; the access to these properties is very frequently done by different threads.
It is more efficient use the same object (for the lock statement) for each property?
private readonly object padlock = new object();
private string name;
private int age;
public string Name
{
get
{
lock(padlock)
return name;
}
set
{
lock(padlock)
name = value;
}
}
public int Age
{
get
{
lock(padlock)
return age;
}
set
{
lock(padlock)
age = value;
}
}
Or to use a different object for each property?
private readonly object padlockName = new object();
private readonly object padlockAge = new object();
private string name;
private int age;
public string Name
{
get
{
lock(padlockName)
return name;
}
set
{
lock(padlockName)
name = value;
}
}
public int Age
{
get
{
lock(padlockAge)
return age;
}
set
{
lock(padlockAge)
age = value;
}
}
The second version makes any sense?
I hesitate to even answer the question you've asked, because I doubt that either of these locking patterns will ensure correctness in your application. They don't ensure that the object as a whole is kept in a consistent state - they just ensure that individual properties are not updated concurrently. To put it another way, you've implemented atomic reads and writes in a roundabout way.
For example, say you had an operation that would increment Age. If two different threads did that at once, the final result could be (Age + 1) or (Age + 2).
You should most likely remove locking from within the object, and have callers deal with concurrency issues as appropriate. One easy solution is to lock the entire object for the duration of their interaction with it. eg:
lock(myObj){
myObj.Age++;
myObj.Name = "Bill";
}
Update
To expand on my middle paragraph, the reason that running Age++ on two different threads could give different results is because the ++ operator is not atomic. It is roughly equivalent to this.
int temp = Age;
temp = temp + 1;
Age = temp;
If two threads ran the same thing, it could execute in order like this (for clarity I've changed names of the temp variables):
int temp1 = Age; //thread 1
int temp2 = Age; //thread 2
temp1 = temp1 + 1; //thread 1
temp2 = temp2 + 1; //thread 2
Age = temp1; //thread 1
Age = temp2; //thread 2
The purpose of locking is to ensure that one thread runs the entire read-increment-write sequence before the other thread does. But your locking scheme doesn't do that.
Note, this is highly dependent on how your object is accessed. The ultimate answer will be determined by measuring your performance in your environment and acting on that as well as the needs specific to your domain (although it seems like your concern here is corrupting the variables used to back the properties, not about accessing clusters of properties at the same time).
That said you have to balance out the following:
If you have one object to lock access to all the properties on the object, multiple threads accessing different properties will wait on each other to complete.
If you have one object per property, then accessing different properties will not cause locks to be waiting.
However, I'd say in this case it's moot as it seems like you're more worried about corruption of the values here.
Assignments and reads on a vast majority of types (excluding multi-field value types) are atomic, meaning you won't corrupt them.
That said, in the example above, where you have a read and write of a property of type string (a reference type) and an int, those operations are atomic and cannot be corrupted by reads/writes from multiple threads.

Are C# structs thread safe?

Is a C# struct thread-safe?
For example if there is a:
struct Data
{
int _number;
public int Number { get { return _number; } set { _number = value; } }
public Data(int number) { _number = number; }
}
in another type:
class DadData
{
public Data TheData { get; set; }
}
is property named TheData, thread-safe?
Well - best practice is that structs should always (except in a few very specific scenarios, and even then at risk) be immutable. And immutable data is always thread safe. So if you followed best practice and made this:
struct Data
{
readonly int _number;
public int Number { get { return _number; } }
public Data(int number) { _number = number; }
}
then yes; that is thread-safe. In all other cases the answer is "probably not".
Note also that atomicity rules apply, so even a single read or update to DadData.TheData cannot be assumed to be thread-safe, even with an immutable struct. You could (especially for oversized structs) have one thread reading the struct while another thread re-writes it; without synchronization bad things will happen (eventually).
No, structures in .NET are not intrinsically thread-safe.
However, the copy-by-value semantics that structures have great relevance to this converation.
If you are passing your structures around and assigning them in some way to variables or pass-by-value parameters (no ref or out keywords) then a copy is being used.
Of course, this means that any changes made to the copy are not reflected in the original structure, but it's something to be aware of when passing them around.
If you are accessing the structure directly in a manner that doesn't involve copy-by-value semantics (e.g. accessing a static field which is the type of the structure, and as Marc Gravel points out in his answer, there are many other ways) across multiple threads, then you have to take into account the thread-safety of the instance.
A struct is not any more thread-safe than an ordinary field or variable. If you have at least one thread modifying it, and at least one more thread touching it in any way at the same time, you may end up with unexpected/undefined behaviour.
Also, mutable structs are code smells. Is there some particular reason you need it to be a struct instead of a class? Do you need value-type semantics for this data?
Different threads' direct reads and writes of different members of a mutable struct will not interfere with each other. Different threads' access to the same member via Interlocked methods will behave according to the semantics of those methods. These facts may allow mutable structs to allow thread-safe behavior.
Mutable storage locations holding structs that offer no means of mutation except outright replacement offer no thread-safety whatsoever, except that in cases where a struct holds either a single 32-bit integer or a single object reference, an attempt to read a such a (single-item) struct storage location at the same time as it is being written is guaranteed to read entirely old data or entirely new data. Note that it is not possible to use any of the Interlocked methods with immutable structs--even structs which contain only a single integer or object reference.
No, they are not.
I created very simple app to see if 10/10 producer/consumer threads are accessing same struct variable. And eventually you will see Debugger.Break(); will be hit. Bank balance should never go under 0 value.
namespace StructThreadSafe
{
class Program
{
struct BankBalance
{
public decimal Balance { get; set; }
}
static void Main(string[] args)
{
BankBalance bankBalance = new BankBalance();
bankBalance.Balance = 100;
List<Task> allTasks = new List<Task>();
for (int q = 0; q < 10; q++)
{
Task producer = new Task(() =>
{
for (int i = 0; i < 1000; i++)
{
if (bankBalance.Balance < 0)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
bankBalance.Balance += 5;
Console.WriteLine("++Current Balance: " + bankBalance.Balance);
System.Threading.Thread.Sleep(100);
}
});
allTasks.Add(producer);
}
for (int w = 0; w < 10; w++)
{
Task consumer = new Task(() =>
{
for (int i = 0; i < 1000; i++)
{
if (bankBalance.Balance < 0)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
if (bankBalance.Balance > 15)
{
bankBalance.Balance -= 15;
Console.WriteLine("--Current Balance: " + bankBalance.Balance);
}
else
{
Console.WriteLine("**Current Balance below minimum: " + bankBalance.Balance);
}
System.Threading.Thread.Sleep(100);
}
});
allTasks.Add(consumer);
}
allTasks.ForEach(p => p.Start());
Task.WaitAll(allTasks.ToArray());
}
}
}
No. Why would it be thread-safe? It's just data. It doesn't become thread-safe by magic.

Categories