Any way to make this C # class thread safe without overwriting?

I like the quick way to create classes in C #, where we can easily create members without having to implement get and set code, but (as far as I know) they are not thread safe!

public class SocksEntry { public int Int1 { get; set; } public int Int2 { get; set; } } 

Does C # provide a quick, easy way to add thread safety without having to do this?

 public class SocksEntry { protected object _lock = new object(); // internal private int _int1 = 0; private int _int2 = 0; // accessors protected int Int1 { get { lock (_lock) return _int1; } set { lock (_lock) _int1 = value; } } protected int Int2 { get { lock (_lock) return _int2; } set { lock (_lock) _int2 = value; } } } 

This obviously makes the whole class much bigger and creates a pain compared to non-streaming security!

+6
source share
5 answers

Creating a safe class stream is much more complicated than you might imagine. Perhaps this is not enough to place locks on getters and setters. Therefore, the best practice is the insecurity of the class and the lack of responsibility to the consumer of this class in order to synchronize access to it if it needs thread safety. If the consumer does not need thread safety, then fine, you will not punish application performance just because you created thread safety in the class without even requiring it. Why do you think 99.99% of classes in .NET are not thread safe?

+7
source

In a word, no.

Authorized properties are great, but when you use restrictions, this is.

However, you can create a Visual Studio fragment (e.g. prop ) that will write boiler room code for you.

+1
source

I think the thread safety issue you are talking about looks something like this:

 public int Value { get; set; } public void Foo() { if (this.Value > 0) // Read the property and make a decision based on its present value { // Do something with the property, assuming its value has passed your test. // Note that the property value may have been changed by another thread between the previous line and this one. Console.WriteLine(this.Value); } } 

The problem is that the value of a property can be changed between when you learned it and when you use it. This happens whether you use the auto properties, fallback variables, or locks that you have in your question. The correct decision depends on how you want your application to behave (what to do if the value changes between one line and another). A common solution is to cache the value directly in the function in which you use it:

 public int Value { get; set; } public void Foo() { int cachedValue = this.Value; if (cachedValue > 0) { Console.WriteLine(cachedValue ); } } 

However, this will not necessarily be right for what your application should do.

0
source

The simplest and therefore the only correct approach is to make the class immutable , so only read operations are available.

 public sealed class SocksEntry { public int Int1 { get; private set; } public int Int2 { get; private set; } } 

But if this is not possible for a specific business object - expose some business methods, rather than means of defining properties, then it is much easier to synchronize the entire method (think transactions), and not every set of properties, which sometimes makes sense to set alltogether

 // lock entire business transaction if possible public void UpdateEntity(int a, int b) { lock (entityLock) { Int1 = a; Int2 = b; } } 
0
source

In the .NET memory model, reading and writing your own integer types less than or equal to the size of your platform pointer (i.e. int for 32-bit, long for 64-bit) is atomic. Atomic means that you can read and write without using locks, and you will never read or write incomplete (that is, halfway between the write value).

However, .NET does not guarantee that records will be immediately visible to other streams (which means that you can write to stream A, then read on stream B and read the old value). On x86, you get immediate visibility with the architecture, but on other platforms you need to use the volatile or Thread.MemoryBarrier after recording. lock puts a memory barrier in place for you, so you don’t have to worry about it.

Another thing to think about is how you use this class. Although one access is atomic, a lock will still be needed if you want to read or write multiple fields as a single atomic operation. (well, not technically always - there are certain optimizations that you can sometimes do, but stick to simple things while you study)

So, in short: lock is pretty much overkill - you can get rid of it and use volatile / barriers if you need immediate visibility.

0
source

All Articles