Are C# structs thread safe? - c#

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.

Related

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.

Why the following C# multi-threaded code does not output zero though it does in debugger?

class Program
{
private static volatile int value;
public static void Increment()
{
for (int i =0; i <100000; i++)
{
value++;
}
}
public static void Decrement()
{
for (int j =0 ; j < 100000; j++)
{
value--;
}
}
public static void ThreadTest()
{
value = 0;
var incrementThread = new Thread(Increment);
var decrementThread = new Thread(Decrement);
incrementThread.Start();
decrementThread.Start();
incrementThread.Join();
decrementThread.Join();
Console.WriteLine("Value of value {0}", value);
}
static void Main(string[] args)
{
ThreadTest();
}
}
Because it is not supposed to... ++ and -- are not atomic operations (unlike Interlocked.XXXX opreations - Interlocked.Increment).
If you write down each step of ++ and -- and see how both can be intermixed by different threads you'll see why:
increment
1: load value to temp
2: add temp, 1
3: store temp to value
decrement
4: load value to temp2
5: substruct temp2, 1
6: store temp2 to value
So if order is 1,2,3,4,5,6 you get value = 0; but if order is 1,2,4,5,6,3 you get value = 1.
Only trying to make the things simpler... I fought this issue back in the day as well :D
Volatile ensure you read the latest value, and when you write all threads see that new value (and that is what volatile operations are for), but it doesn't ensure that between the read and the write, other thread is not going to modify the value. In the other hand, Interlocked (that provides atomic operations) does ensure it.
Volatile operations are good, when for example a thread or threads read and other modify. For example if you have a volatile Boolean _disposed flag in your class, so if one thread dispose it, it's marked as disposed for all threads straight away.

Basic locking question in C#

The classes:
public class SomeCollection
{
public void IteratorReset()
{
index = -1;
}
public bool IteratorNext()
{
index++;
return index < Count;
}
public int Count
{
get
{
return floatCollection.Count;
}
}
public float CurrentValue
{
get
{
return floatCollection[index];
}
}
public int CurrentIndex
{
get
{
return intCollection[index];
}
}
}
Class that holds reference to 'SomeCollection':
public class ThreadUnsafeClass
{
public SomeCollection CollectionObj
{
get
{
return collectionObj;
}
}
}
Classes ClassA, ClassB and ClassC contain the following loop that iterates over CollectionObj:
for (threadUnsafeClass.CollectionObj.IteratorReset(); threadUnsafeClass.CollectionObj.IteratorNext(); )
{
int currentIntIndex = threadUnsafeClass.CollectionObj.CurrentIndex;
float currentfloatValue = threadUnsafeClass.CollectionObj.CurrentValue;
// ...
}
Since I'm only reading CollectionObj in the 3 classes, I'm using multithreading for speedup, but I'm not quite sure how to enforce thread safety. I added a lock in ThreadUnsafeClass when retrieving CollectionObj, but the application throws an out of range exception.
Any help is appreciated.
Thank you !
You're only reading the CollectionObj property, but then you're mutating the object that the value refers to. See this bit:
for (threadUnsafeClass.CollectionObj.IteratorReset();
threadUnsafeClass.CollectionObj.IteratorNext(); )
Both IteratorReset and IteratorNext mutate SomeCollection by changing the value of index. Basically, you can't do this safely with your current code. Several threads could all call IteratorNext() at the same time, for example. The first call returns true, but before that thread gets a chance to read the values, the other threads make the index invalid.
Why are you using the collection itself for iteration? Typically you'd implement IEnumerable<T> and return a new object in GetEnumerator. That way different threads could each get a different object representing "their" cursor over the same collection. They could all iterate over it, and all see all the values.
The SomeCollection object is being referenced by each of the three classes A,B, and C, each of which is going to try and increment the internal index, causing the error(s). That said, you should be able to read objects in an array from multiple threads with something like the following:
public static object[] sharedList = new object[]{1,2,3,4,5};
public void Worker()
{
int localSum=0;
for(int i=0; i<sharedList.length; i++){
localSum += (int)sharedList[i];
}
}
The important thing here is that each thread will maintain it's own location within the array, unlike with the collectionObj.
Locking the CollectionObj property won't help. One possible problem is that all 3 threads are calling IteratorReset(), which sets the index to -1. Imagine the scenario where A starts the for loop, and gets to the first line in the loop before getting interrupted. Now B comes in and calls IteratorReset(), then gets interrupted to let A run again. Thread A executes the CurrentIndex property, which internally uses index = -1 due to B running. Boom, out of range exception.
There are other ways this can generate bad results, but that's probably the easiest to see. Is the intention to have all three threads go through each item on their own? Or are you expecting A, B, and C to divide up the work (like a consumer queue)?

Static Function Concurrency ASP.NET

If you have two threads invoking a static function at the same moment in time, is there a concurrency risk? And if that function uses a static member of the class, is there even a bigger problem?
Are the two calls seperated from each other? (the function is like copied for the two threads?)
Are they automatically queued?
For instance in next example, is there a risk?
private static int a = 5;
public static int Sum()
{
int b = 4;
a = 9;
int c = a + b;
return c;
}
And next example, is there a risk?
public static int Sum2()
{
int a = 5;
int b = 4;
int c = a + b;
return c;
}
Update: And indeed, if both functions are in the same class, what is the risk then?
thx, Lieven Cardoen
Yes, there is a concurrency risk when you modify a static variable in static methods.
The static functions themselves have distinct sets of local variables, but any static variables are shared.
In your specific samples you're not being exposed, but that's just because you're using constants (and assigning the same values to them). Change the code sample slightly and you'll be exposed.
Edit:
If you call both Sum1() AND Sum2() from different threads you're in trouble, there's no way to guarantee the value of a and b in this statement: int c = a + b;
private static int a = 5;
public static int Sum1()
{
int b = 4;
a = 9;
int c = a + b;
return c;
}
public static int Sum2()
{
int b = 4;
int c = a + b;
return c;
}
You can also achieve concurrency problems with multiple invocations of a single method like this:
public static int Sum3(int currentA)
{
a = currentA;
int b = 4;
int c = a + b;
int d = a * b; // a may have changed here
return c + d;
}
The issue here is that the value of a may change mid-method due to other invocations changing it.
See here for a discussion on local variables. before your edit neither of the above methods themselves presented a concurrency risk; the local variables are all independent per call; the shared state (static int a) is visible to multiple threads, but you don't mutate it, and you only read it once.
If you did something like:
if(a > 5) {
Console.WriteLine(a + " is greater than 5");
} // could write "1 is greater than 5"
it would (in theory) not be safe, as the value of a could be changed by another thread - you would typically either synchronize access (via lock etc), or take a snapshot:
int tmp = a;
if(tmp > 5) {
Console.WriteLine(tmp + " is greater than 5");
}
If you are editing the value, you would almost certainly require synchronization.
Yes, there is a risk. That's why you'll see in MSDN doc, it will often say "This class is threadsafe for static members" (or something like that). It means when MS wrote the code, they intentionally used synchronization primitives to make the static members threadsafe. This is common when writing libraries and frameworks, because it is easier to make static members threadsafe than instance members, because you don't know what the library user is going to want to do with instances. If they made instance members threadsafe for many of the library classes, they would put too many restrictions on you ... so often they let you handle it.
So you likewise need to make your static members threadsafe (or document that they aren't).
By the way, static constructors are threadsafe in a sense. The CLR will make sure they are called only once and will prevent 2 threads from getting into a static constructor.
EDIT: Marc pointed out in the comments an edge case in which static constructors are not threadsafe. If you use reflection to explicitly call a static constructor, apparently you can call it more than once. So I revise the statement as follows: as long as you are relying on the CLR to decide when to call your static constructor, then the CLR will prevent it from being called more than once, and it will also prevent the static ctor from being called re-entrantly.
In your two examples, there is no thread safety issues because each call to the function will have it's own copy of the local variables on the stack, and in your first example with 'a' being a static variable, you never change 'a', so there is no problem.
If you change the value in 'a' in your first example you will have a potential concurrency problem.
If the scope of the variables is contained within the static function then there is no risk, but variables outside of the function scope (static / shared) DEFINITLY pose a concurrency risk
Static methods in OO are no difference from "just" functions in procedural programming. Unless you store some state inside static variable there is no risk at all.
You put "ASP.NET" in the question title, this blog post is a good summary of the problems when using the ThreadStatic keyword in ASP.NET :
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html

Categories