Does a multithreaded write-once, read-many need a volatile? - c#

Here is the scenario. I've got a class that will be accessed by multiple threads (ASP.NET) that can benefit from storing a result in a write-once, read-many cache. This cached object is the result of an operation that cannot be performed as part of a static initializer, but must wait for the first execution. So I implement a simple null check as seen below. I'm aware that if two threads hit this check at the same moment I will have ExpensiveCalculation calculated twice, but that isn't the end of the world. My question is, do I need to worry about the static _cachedResult still being seen as null by other threads due to optimizations or other thread caching. Once written, the object is only ever read so I don't think full-scale locking is needed.
public class Bippi
{
private static ExpensiveCalculation _cachedResult;
public int DoSomething(Something arg)
{
// calculate only once. recalculating is not harmful, just wastes time.
if (_cachedResult == null);
_cachedResult = new ExpensiveCalculation(arg);
// additional work with both arg and the results of the precalculated
// values of _cachedResult.A, _cachedResult.B, and _cachedResult.C
int someResult = _cachedResult.A + _cachedResult.B + _cachedResult.C + arg.ChangableProp;
return someResult;
}
}
public class ExpensiveCalculation
{
public int A { get; private set; }
public int B { get; private set; }
public int C { get; private set; }
public ExpensiveCalculation(Something arg)
{
// arg is used to calculate A, B, and C
}
}
Additional notes, this is in a .NET 4.0 application.

My question is, do I need to worry about the static _cachedResult still being seen as null by other threads due to optimizations or other thread caching.
Yes, you do. That's one of the primary reasons volatile exists.
And it's worth mentioning that uncontested locks add an entirely negligible performance cost, so there's really no reason to just to just lock the null check and resource generation, as it's almost certainly not going to cause any performance problems, and makes the program much easier to reason about.
And the best solution is to avoid the question entirely and use a higher level of abstraction that is specifically designed to solve the exact problem that you have. In this case, that means Lazy. You can create a Lazy object that defines how to create your expensive resource, access it wherever you need the object, and the Lazy implementation becomes responsible for ensuring that the resource is created no more than once, and that it is properly exposed to the code asking for said resource, and that it is handled efficiently.

You need not need volatile, you - especially - need a memory barrier so that the processor caches synchronize.

I think you can altogether optimistically avoid locking, and yet avoid volatile performance penalties. You can test for nullability in a two-step fashion.
object readonly _cachedResultLock = new object();
...
if (_cachedResult == null)
{
lock(_cachedResultLock)
{
if (_cachedResult == null)
{
_cachedResult = new ExpensiveCalculation(arg);
}
}
}
Here most of the time you will not reach lock and will not serialize access. You may serialize access only on first access - but will guarantee that work is not wasted (though may cause another thread to wait a bit while first one finishes ExpensiveCalculation).

Related

Proper way to synchronize a property's value in a multi-threaded application

I've recently started revisiting some of my old multi-threaded code and wondering if it's all safe and correct (No issues in production yet...). In particular am I handling object references correctly? I've read a ton of examples using simple primitives like integers, but not a lot pertaining to references and any possible nuances.
First, I recently learned that object reference assignments are atomic, at least on a 64 bit machine which is all I'm focused on for this particular application. Previously, I was locking class properties' get/sets to avoid corrupting the reference as I didn't realize reference assignments were atomic.
For example:
// Immutable collection of options for a Contact
public class ContactOptions
{
public string Email { get; }
public string PhoneNumber { get; }
}
// Sample class that implements the Options
public class Contact
{
private readonly object OptionsLock = new object();
private ContactOptions _Options;
public ContactOptions Options { get { lock(OptionsLock) { return _Options; } }
set { lock(OptionsLock) { _Options = value; } } };
}
Now that I know that a reference assignment is atomic, I thought "great, time to remove these ugly and unnecessary locks!"
Then I read further and learned of synchronization of memory between threads. Now I'm back to keeping the locks to ensure the data doesn't go stale when accessing it. For example, if I access a Contact's Options, I want to ensure I'm always receiving the latest set of Options assigned.
Questions:
Correct me if I'm wrong here, but the above code does ensure that I'm achieving the goal of getting the latest value of Options when I get it in a thread safe manner? Any other issues using this method?
I believe there is some overhead with the lock (Converts to Monitor.Enter/Exit). I thought I could use Interlocked for a nominal performance gain, but more importantly to me, a cleaner set of code. Would the following work to achieve synchronization?
private ContactOptions _Options;
public ContactOptions Options {
get { return Interlocked.CompareExchange(ref _Options, null, null); }
set { Interlocked.Exchange(ref _Options, value); } }
Since a reference assignment is atomic, is the synchronization (using either lock or Interlocked) necessary when assigning the reference? If I omit the set logic and only maintain the get, will I still maintain atomicity and synchronization? My hopeful thinking is that the lock/Interlock usage in the get would provide the synchronization I'm looking for. I've tried writing sample programs to force stale value scenarios, but I couldn't get it done reliably.
private ContactOptions _Options;
public ContactOptions Options {
get { return Interlocked.CompareExchange(ref _Options, null, null); }
set { _Options = value; } }
Side Notes:
The ContactOptions class is deliberately immutable as I don't want to have to synchronize or worry about atomicity within the options themselves. They may contain any kind of data type, so I think it's a lot cleaner/safer to assign a new set of Options when a change is necessary.
I'm familiar of the non-atomic implications of getting a value, working with that value, then setting the value. Consider the following snippet:
public class SomeInteger
{
private readonly object ValueLock = new object();
private int _Value;
public int Value { get { lock(ValueLock) { return _Value; } }
private set { lock(ValueLock) { _Value = value; } } };
// WRONG
public void manipulateBad()
{
Value++;
}
// OK
public void manipulateOk()
{
lock (ValueLock)
{
Value++;
// Or, even better: _Value++; // And remove the lock around the setter
}
}
}
Point being, I'm really only focused on the memory synchronization issue.
SOLUTION:
I went with the Volatile.Read and Volatile.Write methods as they do make the code more explicit, they're cleaner than Interlocked and lock, and they're faster than that aforementioned.
// Sample class that implements the Options
public class Contact
{
public ContactOptions Options { get { return Volatile.Read(ref _Options); } set { Volatile.Write(ref _Options, value); } }
private ContactOptions _Options;
}
Yes, the lock (OptionsLock) ensures that all threads will see the latest value of the Options, because memory barriers are inserted when entering and exiting the lock.
Replacing the lock with methods of the Interlocked or the Volatile class would serve equally well the latest-value-visibility goal. Memory barriers are inserted by these methods as well. I think that using the Volatile communicates better the intentions of the code:
public ContactOptions Options
{
get => Volatile.Read(ref _Options);
set => Volatile.Write(ref _Options, value);
}
Omitting the barrier in either the get or the set accessor puts you automatically in the big black forest of memory models, cache coherency protocols and CPU architectures. In order to know if it's safe to omit it, intricate knowledge of the targeted hardware/OS configuration is required. You will need either an expert's advice, or to become an expert yourself. If you prefer to stay in the realm of software development, don't omit the barrier!
Correct me if I'm wrong here, but the above code does ensure that I'm achieving the goal of getting the latest value of Options when I get it in a thread safe manner? Any other issues using this method?
Yes, locks will emit memory barriers, so it will ensure the value is read from memory. There are no real issues other than potentially being more conservative than it has to be. But I have a saying, if in doubt, use a lock.
I believe there is some overhead with the lock (Converts to Monitor.Enter/Exit). I thought I could use Interlocked for a nominal performance gain, but more importantly to me, a cleaner set of code. Would the following work to achieve synchronization?
Interlocked should also emit memory barriers, so I would think this should do more or less the same thing.
Since a reference assignment is atomic, is the synchronization (using either lock or Interlocked) necessary when assigning the reference? If I omit the set logic and only maintain the get, will I still maintain atomicity and synchronization? My hopeful thinking is that the lock/Interlock usage in the get would provide the synchronization I'm looking for. I've tried writing sample programs to force stale value scenarios, but I couldn't get it done reliably.
I would think that just making the field volatile should be sufficient in this scenario. As far as I understand it the problem with "stale values" is somewhat exaggerated, the cache coherency protocols should take care of most issues.
To my knowledge, the main problem is preventing the compiler from just put the value in a register and not do any subsequent load at all. And that volatile should prevent this, forcing the compiler to issue a load each time it is read. But this would mostly be an issue when repeatedly checking a value in a loop.
But it is not very useful to look at just a single property. Problems more often crop up when you have multiple values that needs to be synchronized. A potential issue is reordering instructions by the compiler or processor. Locks & memory barriers prevent such reordering, but if that is a potential issue, it is probably better to lock a larger section of code.
Overall I consider it prudent to be paranoid when dealing with multiple threads. It is probably better to use to much synchronization than to little. One exception would be deadlocks that may be caused by having too many locks. My recommendation regarding this is to be very careful what you are calling when holding a lock. Ideally a lock should only be held for a short, predictable, time.
Also keep using pure functions and immutable data structures. These are a great way to avoid worrying about threading issues.

Preventing concurrent access to an object, that gets handed around

Think of a network of nodes (update: 'network of nodes' meaning objects in the same application domain, not a network of independent applications) passing objects to each other (and doing some processing on them). Is there a pattern in C# for restricting the access to an object to only the node that is actually processing it?
Main motivation: Ensuring thread-safety (no concurrent access) and object consistency (regarding the data stored in it).
V1: I thought of something like this:
class TransferredObject
{
public class AuthLock
{
public bool AllowOwnerChange { get; private set; }
public void Unlock() { AllowOwnerChange = true; }
}
private AuthLock currentOwner;
public AuthLock Own()
{
if (currentOwner != null && !currentOwner.AllowOwnerChange)
throw new Exception("Cannot change owner, current lock is not released.");
return currentOwner = new AuthLock();
}
public void DoSomething(AuthLock authentification)
{
if (currentOwner != authentification)
throw new Exception("Don't you dare!");
// be sure, that this is only executed by the one holding the lock
// Do something...
}
}
class ProcessingNode
{
public void UseTheObject(TransferredObject x)
{
// take ownership
var auth = x.Own();
// do processing
x.DoSomething(auth);
// release ownership
auth.Unlock();
}
}
V2: Pretty much overhead - a less 'strict' implementation would perhaps be to ignore the checking and rely on the "lock/unlock" logic:
class TransferredObject
{
private bool isLocked;
public Lock()
{
if(isLocked)
throw new Exception("Cannot lock, object is already locked.");
isLocked = true;
}
public Unlock() { isLocked = false; }
public void DoSomething()
{
if (isLocked)
throw new Exception("Don't you dare!");
// Do something...
}
}
class ProcessingNode
{
public void UseTheObject(TransferredObject x)
{
// take ownership
x.Lock = true;
// do processing
x.DoSomething();
// release ownership
x.Unlock = true;
}
}
However: This looks a bit unintuitive (and having to pass an the auth instance with ervery call is ugly). Is there a better approach? Or is this a problem 'made by design'?
To clarify your question: you seek to implement the rental threading model in C#. A brief explanation of different ways to handle concurrent access to an object would likely be helpful.
Single-threaded: all accesses to the object must happen on the main thread.
Free-threaded: any access to the object may happen on any thread; the developer of the object is responsible for ensuring the internal consistency of the object. The developer of the code consuming the object is responsible for ensuring that "external consistency" is maintained. (For example, a free-threaded dictionary must maintain its internal state consistently when adds and removes happen on multiple threads. An external caller must recognize that the answer to the question "do you contain this key?" might change due to an edit from another thread.)
Apartment threaded: all accesses to a given instance of an object must happen on the thread that created the object, but different instances can be affinitized to different threads. The developer of the object must ensure that internal state which is shared between objects is safe for multithreaded access but state which is associated with a given instance will only ever be read or written from a single thread. Typically UI controls are apartment threaded and must be in the apartment of the UI thread.
Rental threaded: access to a given instance of an object must happen from only a single thread at any one time, but which thread that is may change over time
So now let's consider some questions that you should be asking:
Is the rental model a reasonable way to simplify my life, as the author of an object?
Possibly.
The point of the rental model is to achieve some of the benefits of multithreading without taking on the cost of implementing and testing a free-threaded model. Whether those increased benefits and lowered costs are a good fit, I don't know. I personally am skeptical of the value of shared memory in multithreaded situations; I think the whole thing is a bad idea. But if you're bought into the crazy idea that multiple threads of control in one program modifying shared memory is goodness, then maybe the rental model is for you.
The code you are writing is essentially an aid to the caller of your object to make it easier for the caller to obey the rules of the rental model and easier to debug the problem when they stray. By providing that aid to them you lower their costs, at some moderate increase to your own costs.
The idea of implementing such an aid is a good one. The original implementations of VBScript and JScript at Microsoft back in the 1990s used a variation on the apartment model, whereby a script engine would transit from a free-threaded mode into an apartment-threaded mode. We wrote a lot of code to detect callers that were violating the rules of our model and produce errors immediately, rather than allowing the violation to produce undefined behaviour at some unspecified point in the future.
Is my code correct?
No. It's not threadsafe! The code that enforces the rental model and detects violations of it cannot itself assume that the caller is correctly using the rental model! You need to introduce memory barriers to ensure that the various threads reading and writing your lock bools are not moving those reads and writes around in time. Your Own method is chock full of race conditions. This code needs to be very, very carefully designed and reviewed by an expert.
My recommendation - assuming again that you wish to pursue a shared memory multithreaded solution at all - is to eliminate the redundant bool; if the object is unowned then the owner should be null. I don't usually advocate a low-lock solution, but in this case you might consider looking at Interlocked.CompareExchange to do an atomic compare-and-swap on the field with a new owner. If the compare to null fails then the user of your API has a race condition which violates the rental model. This introduces a memory barrier.
Maybe your example is too simplified and you really need this complex ownership thing, but the following code should do the job:
class TransferredObject
{
private object _lockObject = new object();
public void DoSomething()
{
lock(_lockObject)
{
// TODO: your code here...
}
}
}
Your TransferredObject has an atomic method DoSomething that changes some state(s) and should not run multiple times at the same time. So, just put a lock into it to synchronize the critical section.
See http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.90%29.aspx

How to make static method thread safe?

I have written a static class which is a repository of some functions which I am calling from different class.
public static class CommonStructures
{
public struct SendMailParameters
{
public string To { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public string Attachment { get; set; }
}
}
public static class CommonFunctions
{
private static readonly object LockObj = new object();
public static bool SendMail(SendMailParameters sendMailParam)
{
lock (LockObj)
{
try
{
//send mail
return true;
}
catch (Exception ex)
{
//some exception handling
return false;
}
}
}
private static readonly object LockObjCommonFunction2 = new object();
public static int CommonFunction2(int i)
{
lock (LockObjCommonFunction2)
{
int returnValue = 0;
try
{
//send operation
return returnValue;
}
catch (Exception ex)
{
//some exception handling
return returnValue;
}
}
}
}
Question 1: For my second method CommonFunction2, do I use a new static lock i.e. LockObjCommonFunction2 in this example or can I reuse the same lock object LockObj defined at the begining of the function.
Question 2: Is there anything which might lead to threading related issues or can I improve the code to be safe thread.
Quesiton 3: Can there be any issues in passing common class instead of struct.. in this example SendMailParameters( which i make use of wrapping up all parameters, instead of having multiple parameters to the SendMail function)?
Regards,
MH
Question 1: For my second method CommonFunction2, do I use a new
static lock i.e. LockObjCommonFunction2 in this example or can I reuse
the same lock object LockObj defined at the begining of the function.
If you want to synchronize these two methods, then you need to use the same lock for them. Example, if thread1 is accessing your Method1, and thread2 is accessing your Method2 and you want them to not concurrently access both insides, use the same lock. But, if you just want to restrict concurrent access to just either Method1 or 2, use different locks.
Question 2: Is there anything which might lead to threading related
issues or can I improve the code to be safe thread.
Always remember that shared resources (eg. static variables, files) are not thread-safe since they are easily accessed by all threads, thus you need to apply any kind of synchronization (via locks, signals, mutex, etc).
Quesiton 3: Can there be any issues in passing common class instead of
struct.. in this example SendMailParameters( which i make use of
wrapping up all parameters, instead of having multiple parameters to
the SendMail function)?
As long as you apply proper synchronizations, it would be thread-safe. For structs, look at this as a reference.
Bottomline is that you need to apply correct synchronizations for anything that in a shared memory. Also you should always take note of the scope the thread you are spawning and the state of the variables each method is using. Do they change the state or just depend on the internal state of the variable? Does the thread always create an object, although it's static/shared? If yes, then it should be thread-safe. Otherwise, if it just reuses that certain shared resource, then you should apply proper synchronization. And most of all, even without a shared resource, deadlocks could still happen, so remember the basic rules in C# to avoid deadlocks. P.S. thanks to Euphoric for sharing Eric Lippert's article.
But be careful with your synchronizations. As much as possible, limit their scopes to only where the shared resource is being modified. Because it could result to inconvenient bottlenecks to your application where performance will be greatly affected.
static readonly object _lock = new object();
static SomeClass sc = new SomeClass();
static void workerMethod()
{
//assuming this method is called by multiple threads
longProcessingMethod();
modifySharedResource(sc);
}
static void modifySharedResource(SomeClass sc)
{
//do something
lock (_lock)
{
//where sc is modified
}
}
static void longProcessingMethod()
{
//a long process
}
You can reuse the same lock object as many times as you like, but that means that none of the areas of code surrounded by that same lock can be accessed at the same time by various threads. So you need to plan accordingly, and carefully.
Sometimes it's better to use one lock object for multiple location, if there are multiple functions which edit the same array, for instance. Other times, more than one lock object is better, because even if one section of code is locked, the other can still run.
Multi-threaded coding is all about careful planning...
To be super duper safe, at the expense of potentially writing much slower code... you can add an accessor to your static class surround by a lock. That way you can make sure that none of the methods of that class will ever be called by two threads at the same time. It's pretty brute force, and definitely a 'no-no' for professionals. But if you're just getting familiar with how these things work, it's not a bad place to start learning.
1) As to first it depends on what you want to have:
As is (two separate lock objects) - no two threads will execute the same method at the same time but they can execute different methods at the same time.
If you change to have single lock object then no two threads will execute those sections under shared locking object.
2) In your snippet there is nothing that strikes me as wrong - but there is not much of code. If your repository calls methods from itself then you can have a problem and there is a world of issues that you can run into :)
3) As to structs I would not use them. Use classes it is better/easier that way there is another bag of issues related with structs you just don't need those problems.
The number of lock objects to use depends on what kind of data you're trying to protect. If you have several variables that are read/updated on multiple threads, you should use a separate lock object for each independent variable. So if you have 10 variables that form 6 independent variable groups (as far as how you intend to read / write them), you should use 6 lock objects for best performance. (An independent variable is one that's read / written on multiple threads without affecting the value of other variables. If 2 variables must be read together for a given action, they're dependent on each other so they'd have to be locked together. I hope this is not too confusing.)
Locked regions should be as short as possible for maximum performance - every time you lock a region of code, no other thread can enter that region until the lock is released. If you have a number of independent variables but use too few lock objects, your performance will suffer because your locked regions will grow longer.
Having more lock objects allows for higher parallelism since each thread can read / write a different independent variable - threads will only have to wait on each other if they try to read / write variables that are dependent on each other (and thus are locked through the same lock object).
In your code you must be careful with your SendMailParameters input parameter - if this is a reference type (class, not struct) you must make sure that its properties are locked or that it isn't accessed on multiple threads. If it's a reference type, it's just a pointer and without locking inside its property getters / setters, multiple threads may attempt to read / write some properties of the same instance. If this happens, your SendMail() function may end up using a corrupted instance. It's not enough to simply have a lock inside SendMail() - properties and methods of SendMailParameters must be protected as well.

How to easy make this counter property thread safe?

I have property definition in class where i have only Counters, this must be thread-safe and this isn't because get and set is not in same lock, How to do that?
private int _DoneCounter;
public int DoneCounter
{
get
{
return _DoneCounter;
}
set
{
lock (sync)
{
_DoneCounter = value;
}
}
}
If you're looking to implement the property in such a way that DoneCounter = DoneCounter + 1 is guaranteed not to be subject to race conditions, it can't be done in the property's implementation. That operation is not atomic, it actually three distinct steps:
Retrieve the value of DoneCounter.
Add 1
Store the result in DoneCounter.
You have to guard against the possibility that a context switch could happen in between any of those steps. Locking inside the getter or setter won't help, because that lock's scope exists entirely within one of the steps (either 1 or 3). If you want to make sure all three steps happen together without being interrupted, then your synchronization has to cover all three steps. Which means it has to happen in a context that contains all three of them. That's probably going to end up being code that does not belong to whatever class contains the DoneCounter property.
It is the responsibility of the person using your object to take care of thread safety. In general, no class that has read/write fields or properties can be made "thread-safe" in this manner. However, if you can change the class's interface so that setters aren't necessary, then it is possible to make it more thread-safe. For example, if you know that DoneCounter only increments and decrements, then you could re-implement it like so:
private int _doneCounter;
public int DoneCounter { get { return _doneCounter; } }
public int IncrementDoneCounter() { return Interlocked.Increment(ref _doneCounter); }
public int DecrementDoneCounter() { return Interlocked.Decrement(ref _doneCounter); }
Using the Interlocked class provides for atomic operations, i.e. inherently threadsafe as in this LinqPad example:
void Main()
{
var counters = new Counters();
counters.DoneCounter += 34;
var val = counters.DoneCounter;
val.Dump(); // 34
}
public class Counters
{
int doneCounter = 0;
public int DoneCounter
{
get { return Interlocked.CompareExchange(ref doneCounter, 0, 0); }
set { Interlocked.Exchange(ref doneCounter, value); }
}
}
If you're expecting not just that some threads will occasionally write to the counter at the same time, but that lots of threads will keep doing so, then you want to have several counters, at least one cache-line apart from each other, and have different threads write to different counters, summing them when you need the tally.
This keeps most threads out of each others ways, which stops them from flushing each others values out of the cores, and slowing each other up. (You still need interlocked unless you can guarantee each thread will stay separate).
For the vast majority of cases, you just need to make sure the occasional bit of contention doesn't mess up the values, in which case Sean U's answer is better in every way (striped counters like this are slower for uncontested use).
What exactly are you trying to do with the counters? Locks don't really do much with integer properties, since reads and writes of integers are atomic with or without locking. The only benefit one can get from locks is the addition of memory barriers; one can achieve the same effect by using Threading.Thread.MemoryBarrier() before and after you read or write a shared variable.
I suspect your real problem is that you are trying to do something like "DoneCounter+=1", which--even with locking--would perform the following sequence of events:
Acquire lock
Get _DoneCounter
Release lock
Add one to value that was read
Acquire lock
Set _DoneCounter to computed value
Release lock
Not very helpful, since the value might change between the get and set. What would be needed would be a method that would perform the get, computation, and set without any intervening operations. There are three ways this can be accomplished:
Acquire and keep a lock during the whole operation
Use Threading.Interlocked.Increment to add a value to _Counter
Use a Threading.Interlocked.CompareExchange loop to update _Counter
Using any of these approaches, it's possible to compute a new value of _Counter based on the old value, in such a fashion that the value written is guaranteed to be based upon the value _Counter had at the time of the write.
You could declare the _DoneCounter variable as "volatile", to make it thread-safe. See this:
http://msdn.microsoft.com/en-us/library/x13ttww7%28v=vs.71%29.aspx

C# lock free coding sanity check

UPDATED: now using a read-only collection based on comments below
I believe that the following code should be thread safe "lock free" code, but want to make sure I'm not missing something...
public class ViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged and other boring stuff goes here...
private volatile List<string> _data;
public IEnumerable<string> Data
{
get { return _data; }
}
//this function is called on a timer and runs on a background thread
private void RefreshData()
{
List<string> newData = ACallToAService();
_data = newData.AsReadOnly();
OnPropertyChanged("Data"); // yes, this dispatches the to UI thread
}
}
Specifically, I know that I could use a lock(_lock) or even an Interlocked.Exchange() but I don't believe that there is a need for it in this case. The volatile keyword should be sufficient (to make sure the value isn't cached), no? Can someone please confirm this, or else let me know what I don't understand about threading :)
I have no idea whether that is "safe" or not; it depends on precisely what you mean by "safe". For example, if you define "safe" as "a consistent ordering of all volatile writes is guaranteed to be observed from all threads", then your program is not guaranteed to be "safe" on all hardware.
The best practice here is to use a lock unless you have an extremely good reason not to. What is your extremely good reason to write this risky code?
UPDATE: My point is that low-lock or no-lock code is extremely risky and that only a small number of people in the world actually understand it. Let me give you an example, from Joe Duffy:
// deeply broken, do not use!
class Singleton {
private static object slock = new object();
private static Singleton instance;
private static bool initialized;
private Singleton() {}
public Instance {
get {
if (!initialized) {
lock (slock) {
if (!initialized) {
instance = new Singleton();
initialized = true;
}
}
}
return instance;
}
}
}
This code is broken; it is perfectly legal for a correct implementation of the C# compiler to write you a program that returns null for the instance. Can you see how? If not, then you have no business doing low-lock or no-lock programming; you will get it wrong.
I can't figure out this stuff myself; it breaks my brain. That's why I try to never do low-lock programming that departs in any way from standard practices that have been analyzed by experts.
It depends on what the intent is. The get/set of the list is atomic (even without volatile) and non-cached (volatile), but callers can mutate the list, which is not guaranteed thread-safe.
There is also a race condition that could lose data:
obj.Data.Add(value);
Here value could easily be discarded.
I would use an immutable (read-only) collection.
I think that if you have only two threads like you described, your code is correct and safe. And also you don't need that volatile, it is useless here.
But please don't call it "thread safe", as it is safe only for your two threads using it your special way.
I believe that this is safe in itself (even without volatile), however there may be issues depending on how other threads use the Data property.
Provided that you can guarantee that all other threads read and cache the value of Data once before doing enumeration on it (and don't try to cast it to some broader interface to perform other operations), and make no consistency assumptions for a second access to the property, then you should be ok. If you can't make that guarantee (and it'd be hard to make that guarantee if eg. one of the users is the framework itself via data-binding, and hence code that you do not control), then you can't say that it's safe.
For example, this would be safe:
foreach (var item in x.Data)
{
// do something with item
}
And this would be safe (provided that the JIT isn't allowed to optimise away the local, which I think is the case):
var data = x.Data;
var item1 = FindItem(data, a);
var item2 = FindItem(data, b);
DoSomething(item1, item2);
The above two might act on stale data, but it will always be consistent data. But this would not necessarily be safe:
var item1 = FindItem(x.Data, a);
var item2 = FindItem(x.Data, b);
DoSomething(item1, item2);
This one could possibly be searching two different states of the collection (before and after some thread replaces it), so it may not be safe to operate on items found in each separate enumeration, as they may not be consistent with each other.
The issue would be worse with a broader interface; eg. if Data exposed IList<T> you'd have to watch for consistency of Count and indexer operations as well.

Categories

Resources