Switching from Lock to ReaderWriterLock - c#

Is it possible to easily convert a property in a C# that uses locking in its getter and setter so that it uses a ReaderWriterLock instead?
For instance, consider the following property:
object numLock = new object();
public int Num
{
get
{
Lock(numLock)
{
return num;
}
}
set
{
Lock(numLock)
{
num = value;
}
}
}
What is the fastest way to change this to allow multiple readers or a single writer. Note that the code that need to be changed contain hundreds of similar properties. So, I'm looking for a simple solution to convert the locking mechanism in these properties in a fast and reliable way.

Related

Solution for thread safe read write updates to static variables with read write synchronization

In my project I'm using some static variables which I use for storing values during the running lifetime of the application. Now, 99% of the time I'm only reading these values but from time to time I also need to update them and this will happen from different threads.
When thinking about what might happen with two different threads trying to access the same property e.g. concurrent read/write, I started to conclude that some form of synchronization would needed in order to avoid unexpected values being returned between different process or some risk of race conditions.
In essence I needed to derive a single source of truth. I realize that some properties are atomic like booleans, but my methodology mostly applies for the purpose of strings.
One of the challenges is that these static variables are referenced in many places and between different classes, so I also had to figure out an efficient way to solve this challenge without lots of code re-write.
I've decided to use concurrent dictionaries:
public static readonly ConcurrentDictionary<string, string> AppRunTimeStringDictionary = new();
public static readonly ConcurrentDictionary<string, int> AppRunTimeIntegerDictionary = new();
public static readonly ConcurrentDictionary<string, bool> AppRunTimeBooleanDictionary = new();
In my program.cs file, during the earliest stages of startup I simply add all of the properties needed for the running app:
DeviceProvisioning.AppRunTimeBooleanDictionary.TryAdd("UseGpsReceiver", false);
DeviceProvisioning.AppRunTimeStringDictionary.TryAdd("Latitude", String.Empty);
DeviceProvisioning.AppRunTimeStringDictionary.TryAdd("Longitude", String.Empty);
Then in one of my classes I hard code these properties:
public static bool? UseGpsReceiver
{
get
{
if (AppRunTimeBooleanDictionary.TryGetValue("UseGpsReceiver", out var returnedValue))
return returnedValue;
return null;
}
}
public static string? Latitude
{
get
{
if (AppRunTimeStringDictionary.TryGetValue("Latitude", out var returnedValue))
return returnedValue;
return null;
}
}
public static string? Longitude
{
get
{
if (AppRunTimeStringDictionary.TryGetValue("Longitude", out var returnedValue))
return returnedValue;
return null;
}
}
Now for updating these properties, which happens rarely but will be done every now and then, I'm updating these in just one location i.e. using a single method. This way I can use this common method and simply add more prperties to the switch case over time.
public static void SetRunTimeSettings(string property, object value)
{
switch (property)
{
case "UseGpsReceiver":
// code block
if (AppRunTimeBooleanDictionary.TryGetValue("UseGpsReceiver", out var useGpsReceiver))
{ AppRunTimeBooleanDictionary.TryUpdate("UseGpsReceiver", (bool)value, useGpsReceiver); }
break;
case "Latitude":
// code block
if (AppRunTimeStringDictionary.TryGetValue("Latitude", out var latitude))
{ AppRunTimeStringDictionary.TryUpdate("Latitude", (string)value, latitude); }
break;
case "Longitude":
// code block
if (AppRunTimeStringDictionary.TryGetValue("Latitude", out var longitude))
{ AppRunTimeStringDictionary.TryUpdate("Latitude", (string)value, longitude); }
break;
}
}
If I want to update a property then I simply invoke the method as such:
MyClassName.SetRunTimeSettings("UseGpsReceiver", true);
MyClassName.SetRunTimeSettings("Latitude", "51.1234");
MyClassName.SetRunTimeSettings("Longitude", "51.5678");
Because the properties themselves are public static then I can use the getter from anywhere in the app.
From my initial testing, everything seems to work.
Perceived advantages in this approach:
Using a separate dictionary for each type of property collection i.e. strings/integers etc, means I can simply add more properties to the dictionary any time in the future without the need for referencing a model class in the dictionary, as opposed to the dictionary below:
public static readonly ConcurrentDictionary<string, myModelClass> AppRunTimeStringDictionary = new();
Use of the concurrent dictionary (my understanding) is that any process trying to read the property value from the dictionary will always get the latest value, if a property is being updated then I have less risk in reading an old value. Not such an issue for structured logging but if I was storing keys/secrets/connection strings or anything else, reading an old value might stop some process from being able to function correctly.
Using the concurrent dictionary means I don't have to hand craft my own locking mechanisms, which many people seem not to like doing.
Dictionary applies its own internal locks on the individual objects, so any property not being updated can still be read by other processes without much delay.
If the public static getter ever returned a null value, my thoughts are it would be better to return a null value rather than returning the wrong value. I could always implement some kind of polly or retry mechanism somewhere from the calling process, some short delay before trying to retrieve the property value again (by which time it should have been updated from the other thread that was currently updating it)
Appreciate there will be other ways to approach this, so really what I'm asking here is whether anyone sees any issue in my approach?
I'm not planning to add that many properties to each dictionary, I just want a way to ensure that reads and writes are happening with some form of synchronization and order.
Your SetRunTimeSettings is awful. It relies on methods that follow the Try* pattern, but it itself does not. Also doing a TryGetValue just to then be able to call TryUpdate is just throwing away all of the value of Try* operators anyway. It's a hack.
And you have a clear bug in the code for the "Longitude" case - you're updating "Latitude" inside.
I'd suggest going old school and just do this:
private static bool? _UseGpsReceiver;
private readonly static object _UseGpsReceiverLock = new();
public static bool? UseGpsReceiver
{
get { lock (_UseGpsReceiverLock) return _UseGpsReceiver; }
set { lock (_UseGpsReceiverLock) _UseGpsReceiver = value; }
}
private static string? _Latitude;
private readonly static object _LatitudeLock = new();
public static string? Latitude
{
get { lock (_LatitudeLock) return _Latitude; }
set { lock (_LatitudeLock) _Latitude = value; }
}
private static string? _Longitude;
private readonly static object _LongitudeLock = new();
public static string? Longitude
{
get { lock (_LongitudeLock) return _Longitude; }
set { lock (_LongitudeLock) _Longitude = value; }
}
If you don't want to repeat all of the locks then maybe a Locked<T> class might be of use:
public struct Locked<T>
{
public Locked(T value)
{
_value = value;
}
private T _value;
private readonly object _gate = new();
public T Value
{
get { lock (_gate) return _value; }
set { lock (_gate) _value = value; }
}
}
Then you can write this:
private static Locked<bool?> _UseGpsReceiver;
public static bool? UseGpsReceiver
{
get { return _UseGpsReceiver.Value; }
set { _UseGpsReceiver.Value = value; }
}
private static Locked<string?> _Latitude;
public static string? Latitude
{
get { return _Latitude.Value; }
set { _Latitude.Value = value; }
}
private static Locked<string?> _Longitude;
public static string? Longitude
{
get { return _Longitude.Value; }
set { _Longitude.Value = value; }
}
If you are only setting a single string / int / bool at a time, then you don't need to any thread safety. If you are assigning any single value smaller than a machine word, any reading thread will either see the before value or the after value.
However it looks like you intend to set three values at the same time;
MyClassName.SetRunTimeSettings("UseGpsReceiver", true);
MyClassName.SetRunTimeSettings("Latitude", "51.1234");
MyClassName.SetRunTimeSettings("Longitude", "51.5678");
And I assume you want any reader to see either the old values or the new values. In this case you would need some thread synchronisation around every read / write. Which your current code doesn't have.
You could instead store the three values in a class, then update the reference to that instance in one write operation.
public class GpsSettings{
public bool UseGpsReceiver { get; init; }
public double Latitude { get; init; }
public double Longitude { get; init; }
public static GpsSettings Current;
}
...
// write
GpsSettings.Current = new GpsSettings {
UseGpsReceiver = true,
Latitude = 51.1234,
Longitude = 51.5678
};
// read
var gps = GpsSettings.Current;
var location = $"{gps.Latitude}, {gps.Longitude}";
// but never do this;
var location = $"{GpsSettings.Current.Latitude}, {GpsSettings.Current.Longitude}";
Not everyone would agree with me on this one but my personal approach would be to have a single dictionary of the following type:
Dictionary<string, object>
Wrapped in a separate class with the following methods such as AddValue, GetValue, HasKey, HasValue, and UpdateValue with lock statements. Also notice that you'll have to use somewhat generic methods in order to be able to retrieve the value with the actual type and a default value. For example:
public static T GetValue<T>(string key, T defaultValue)
Also, I don't see a problem with your approach but if you want to synchronize things then you'll need n dedicated locks for n dictionaries which I don't think is a clean way; unless I'm missing something, and of course registering multiple dictionaries in design time can be a headache.
Alternatively to using multiple ConcurrentDictionary<string, T> collections, or a single ConcurrentDictionary<string, object>, or the Locked<T> struct shown in Enigmativity's answer, you could just store the values in immutable and recyclable Tuple<T> instances, and store these in private volatile fields:
private static volatile Tuple<bool?> _UseGpsReceiver;
public static bool? UseGpsReceiver
{
get { return _UseGpsReceiver?.Item1; }
set { _UseGpsReceiver = new(value); }
}
private static volatile Tuple<string> _Latitude;
public static string Latitude
{
get { return _Latitude?.Item1; }
set { _Latitude = new(value); }
}
private static volatile Tuple<string> _Longitude;
public static string Longitude
{
get { return _Longitude?.Item1; }
set { _Longitude = new(value); }
}
Pros: Both the reading and the writing are lock-free. An unlimited number of readers and writers can read and update the values at the same time, without contention.
Cons: Every time a value is updated, a new Tuple<T> is instantiated, adding pressure on the .NET garbage collector. This reduces the appeal of this approach in case the values are updated too frequently. Also if you have dozens of properties like these, it might be easy to introduce subtle bugs by omitting the important volatile keyword by mistake.

A static property in static class when used concurrently

I have a static class 'Logger' with a public property called 'LogLevels' as in code below.
When the property is used concurrently in a multi-user or multi-threaded environment, could it cause problems?
Do I need to use thread synchronization for the code within the property 'LogLevels'?
public class Logger
{
private static List<LogLevel> _logLevels = null;
public static List<LogLevel> LogLevels
{
get
{
if (_logLevels == null)
{
_logLevels = new List<LogLevel>();
if (!string.IsNullOrWhiteSpace(System.Configuration.ConfigurationManager.AppSettings["LogLevels"]))
{
string[] lls = System.Configuration.ConfigurationManager.AppSettings["LogLevels"].Split(",".ToCharArray());
foreach (string ll in lls)
{
_logLevels.Add((LogLevel)System.Enum.Parse(typeof(LogLevel), ll));
}
}
}
if (_logLevels.Count == 0)
{
_logLevels.Add(LogLevel.Error);
}
return _logLevels;
}
}
}
UPDATE: I ended up using thread synchronization to solve concurrency problem in a static class, as in code below.
public class Logger
{
private static readonly System.Object _object = new System.Object();
private static List<LogLevel> _logLevels = null;
private static List<LogLevel> LogLevels
{
get
{
//Make sure that in a multi-threaded or multi-user scenario, we do not run into concurrency issues with this code.
lock (_object)
{
if (_logLevels == null)
{
_logLevels = new List<LogLevel>();
if (!string.IsNullOrWhiteSpace(System.Configuration.ConfigurationManager.AppSettings["SimpleDBLogLevelsLogger"]))
{
string[] lls = System.Configuration.ConfigurationManager.AppSettings["SimpleDBLogLevelsLogger"].Split(",".ToCharArray());
foreach (string ll in lls)
{
_logLevels.Add((LogLevel)System.Enum.Parse(typeof(LogLevel), ll));
}
}
}
if (_logLevels.Count == 0)
{
_logLevels.Add(LogLevel.Error);
}
}
return _logLevels;
}
}
}
When the property is used concurrently in a multi-user or multi-threaded environment, could it cause problems?
Absolutely. List<T> is not designed for multiple threads, except for the case where there are just multiple readers (no writers).
Do I need to use thread synchronization for the code within the property 'LogLevels'?
Well that's one approach. Or just initialize it on type initialization, and then return a read-only wrapper around it. (You really don't want multiple threads modifying it.)
Note that in general, doing significant amounts of work in a static constructor is a bad idea. Are you happy enough that if this fails, every access to this property will fail, forever?
This code posses race conditions and cannot be safely executed from multiple threads. The primary problem is the List<T> type is not thread safe yet this code will freely write to. This mean the writes can occur in parallel and hence break the implicit contract of List<T>
The short answer is "yes" and "yes" you do need threads synchronization.
The other question is, why re-invent the wheel? You can use something like log4net or .NET logging framework.

How to synchronize a collection of values in C#

I have inherited some code that has a set of real-time values that are captured over a serial link that runs on a separate thread:
class Data
{
public static int nFooCount;
public static decimal meanValue;
// Lots more of a variety of types.
}
The thread just stores the data into the field with no locking or other synchronization. Looks like a whole sea of race conditions to me. So I want to add some safety to it. The question is, what's best?
I could make the int fields volatile. Can't do that with the decimal types, though. Interlocked can help with that, albeit messily, using boxing. Or I could add a lock object
private static readonly object lockObj = new object();
and then accessor everything. But this locks all the fields even when it will only modify one at a time. I can't lock on primitives and that would be bad form anyway, and adding a lock object for every field would look wasteful. So is there a better way?
You could lock according to required access level using ReaderWriterLockSlim. You could do this better by turning them into a property:
public int Something
{
get {
locker.EnterReadLock();
try {
return something;
} finally {
locker.ExitReadLock();
}
}
set {
locker.EnterWriteLock();
try {
something = value;
} finally {
locker.ExitWriteLock();
}
}
}
This allows for multiple reads and single writes.

Does a lock around a write guarantee fresh read in another thread? (.Net, memory model)

Say I have a property whose setter is protected by a lock, but without any lock around the getter, e.g.
private long _myField;
public long MyProperty
{
get { return _myField; }
set { lock(whatever) _myField = value; }
}
In addition to synchronizing writes (but not reads), the lock, or rather Monitor.Exit, should cause a volatile write. Let's now say we have two threads A and B, and the following sequence happens:
A reads the current value of MyProperty.
B writes a new value to MyProperty.
A reads the current value of MyProperty again.
Q: Is A now guaranteed to see the new value? Or did our lock just ensure that B writes to main memory in a timely manner, but not that other threads read a fresh value? Or could the answer even depend on whether we're running in .Net 2+ or a "weaker" ECMA implementation?
No, since the read does not have the explicit memory barrier, it is not "guaranteed" to see the new value.
You can use a ReaderWriterLockSlim to insure that a) the writes lock each other and b) the reads always pickup the new value.
private readonly ReaderWriterLockSlim _myFieldLock = new ReaderWriterLockSlim();
private long _myField;
public long MyProperty
{
get
{
_myFieldLock.EnterReadLock();
try
{
return _myField;
}
finally
{
_myFieldLock.ExitReadLock();
}
}
set
{
_myFieldLock.EnterWriteLock();
try
{
_myField = value;
}
finally
{
_myFieldLock.ExitWriteLock();
}
}
}
If you used Interlocked.Read in the getter you should always read the new value. See Threading in C# for more information about memory fences

Is This a Good Design for Creating Thread-Safe Classes in C#?

Often, when I want a class which is thread-safe, I do something like the following:
public class ThreadSafeClass
{
private readonly object theLock = new object();
private double propertyA;
public double PropertyA
{
get
{
lock (theLock)
{
return propertyA;
}
}
set
{
lock (theLock)
{
propertyA = value;
}
}
}
private double propertyB;
public double PropertyB
{
get
{
lock (theLock)
{
return propertyB;
}
}
set
{
lock (theLock)
{
propertyB = value;
}
}
}
public void SomeMethod()
{
lock (theLock)
{
PropertyA = 2.0 * PropertyB;
}
}
}
It works, but it is very verbose. Sometimes I even create a lock object for each method and property creating more verbosity and complexity.
I know that it is also possible to lock classes using the Synchronization attribute but I'm not sure how well that scales -- as I often expect to have hundreds of thousands, if not millions, of instances of thread-safe objects. This approach would create a synchronization context for every instance of the class, and requires the class to be derived from ContextBoundObject and therefore could not be derived from anything else -- since C# doesn't allow for multiple inheritance -- which is a show stopper in many cases.
Edit: As several of the responders have emphasized, there is no "silver bullet" thread-safe class design. I'm just trying to understand if the pattern I'm using is one of the good solutions. Of course the best solution in any particular situation is problem dependent. Several of the answers below contain alternative designs which should be considered.
Edit: Moreover, there is more than one definition of thread safety. For example, in my implementation above, the following code would NOT be thread-safe:
var myObject = new ThreadSafeClass();
myObject.PropertyA++; // NOT thread-safe
So, does the class definition above represent a good approach? If not, what would you recommend for a design with similar behavior which would be thread-safe for a similar set of uses?
There is no "one-size-fits-all" solution to the multi-threading problem. Do some research on creating immutable classes and learn about the different synchronization primitives.
This is an example of a semi-immutable or the-programmers-immutable class .
public class ThreadSafeClass
{
public double A { get; private set; }
public double B { get; private set; }
public double C { get; private set; }
public ThreadSafeClass(double a, double b, double c)
{
A = a;
B = b;
C = c;
}
public ThreadSafeClass RecalculateA()
{
return new ThreadSafeClass(2.0 * B, B, C);
}
}
This example moves your synchronization code into another class and serializes access to an instance. In reality, you don't really want more than one thread operating on an object at any given time.
public class ThreadSafeClass
{
public double PropertyA { get; set; }
public double PropertyB { get; set; }
public double PropertyC { get; set; }
private ThreadSafeClass()
{
}
public void ModifyClass()
{
// do stuff
}
public class Synchronizer
{
private ThreadSafeClass instance = new ThreadSafeClass();
private readonly object locker = new object();
public void Execute(Action<ThreadSafeClass> action)
{
lock (locker)
{
action(instance);
}
}
public T Execute<T>(Func<ThreadSafeClass, T> func)
{
lock (locker)
{
return func(instance);
}
}
}
}
Here is a quick example of how you would use it. It may seem a little clunky but it allows you to execute many actions on the instance in one go.
var syn = new ThreadSafeClass.Synchronizer();
syn.Execute(inst => {
inst.PropertyA = 2.0;
inst.PropertyB = 2.0;
inst.PropertyC = 2.0;
});
var a = syn.Execute<double>(inst => {
return inst.PropertyA + inst.PropertyB;
});
I know this might sound like an smart a** answer but ... the BEST way to develop threadsafe classes is to actually know about multithreading, about its implications, its intricacies and what does it implies. There's no silver bullet.
First you need a good reason to use it. Threads are a tool, you don't want to hit everything with your new found hammer.
Secondly, learn about the problems of multithreading... deadlocks, race conditions, starvation and so on
Third, make sure is worth it. I'm talking about benefit/cost.
Finally... be prepared to heavy debugging. Debugging multithreaded code is much more difficult than standard old sequential code. Learn some techniques about how to do that.
Seriously... don't try to multithread (in production scenarios I mean) until you know what you're getting yourself into... It can be a huge mistake.
Edit: You should of course know the synchronization primitives of both the operating system and your language of choice (C# under Windows in this case, I guess).
I'm sorry I'm not giving just the code to just make a class threadsafe. That's because it does not exist. A completely threadsafe class will probably just be slower than just avoiding threads and will probably act as a bottleneck to whatever you're doing... effectively undoing whatever you thing you're achieving by using threads.
Bear in mind that the term "thread safe" is not specific; what you're doing here would be more accurately referred to as "synchronization" through the use of a Monitor lock.
That said, the verbosity around synchronized code is pretty much unavoidable. You could cut down on some of the whitespace in your example by turning things like this:
lock (theLock)
{
propertyB = value;
}
into this:
lock (theLock) propertyB = value;
As to whether or not this is the right approach for you we really need more information. Synchronization is just one approach to "thread safety"; immutable objects, semaphores, etc. are all different mechanisms that fit different use-cases. For the simple example you provide (where it looks like you're trying to ensure the atomicity of a get or set operation), then it looks like you've done the right things, but if your code is intended to be more of an illustration than an example then things may not be as simple.
Since no else seems to be doing it, here is some analysis on your specific design.
Want to read any single property? Threadsafe
Want to update to any single property? Threadsafe
Want to read a single property and then update it based on its original value? Not Threadsafe
Thread 2 could update the value between thread 1's read and update.
Want to update two related properties at the same time? Not Threadsafe
You could end up with Property A having thread 1's value and Property B having thread 2's value.
Thread 1 Update A
Thread 2 Update A
Thread 1 Update B
Thread 2 Update B
Want to read two related properties at the same time? Not Threadsafe
Again, you could be interrupted between the first and second read.
I could continue, but you get the idea. Threadsafety is purely based on how you plan to access the objects and what promises you need to make.
You may find the Interlocked class helpful. It contains several atomic operations.
One thing you could do that could help you avoid the extra code is use something like PostSharp to automatically inject those lock statements into your code, even if you had hundreds of them. All you'd need is one attribute attached to the class, and the attribute's implementation which would add the extra locking variables.
As per my comment above - it gets a little hairier if you want simultaneous readers allowed but only one writer allowed. Note, if you have .NET 3.5, use ReaderWriterLockSlim rather than ReaderWriterLock for this type of pattern.
public class ThreadSafeClass
{
private readonly ReaderWriterLock theLock = new ReaderWriterLock();
private double propertyA;
public double PropertyA
{
get
{
theLock.AcquireReaderLock(Timeout.Infinite);
try
{
return propertyA;
}
finally
{
theLock.ReleaseReaderLock();
}
}
set
{
theLock.AcquireWriterLock(Timeout.Infinite);
try
{
propertyA = value;
}
finally
{
theLock.ReleaseWriterLock();
}
}
}
private double propertyB;
public double PropertyB
{
get
{
theLock.AcquireReaderLock(Timeout.Infinite);
try
{
return propertyB;
}
finally
{
theLock.ReleaseReaderLock();
}
}
set
{
theLock.AcquireWriterLock(Timeout.Infinite);
try
{
propertyB = value;
}
finally
{
theLock.ReleaseWriterLock();
}
}
}
public void SomeMethod()
{
theLock.AcquireWriterLock(Timeout.Infinite);
try
{
theLock.AcquireReaderLock(Timeout.Infinite);
try
{
PropertyA = 2.0 * PropertyB;
}
finally
{
theLock.ReleaseReaderLock();
}
}
finally
{
theLock.ReleaseWriterLock();
}
}
}

Categories