-1

There is a class like so:

public class A{
    public B classB { get; set; }
    ...
}

A is instantiated somewhere as classA.

classA.classB is set and modified by codes I have no control of, those codes may be on different threads.

Now I want to modify classA.classB on the my thread.

Do I need to 1:

lock(classA) lock(classA.classB) {
//my codes that modifies classA.classB
}

Or 2:

lock(classA.classB){
//my codes that modifies classA.classB
}

Basically the question is: Is containing class automatically locked if I lock its members, or it doesn't work like that at all.

Please do NOT tell me:

Well you should use a locking object or a mutex, it may be a solution but it's not related to the question.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
Wenk Hsueh
  • 117
  • 10
  • See [the question here](https://stackoverflow.com/questions/6029804/how-does-lock-work-exactly). `lock` locks the code contained within the lock based on an object. The state of the lock depends on the object, and the object can be used by many locks (but will lock all at once). – ProgrammingLlama Dec 15 '17 at 03:02
  • I just want to make sure when I lock on classB and modify it, nothing wrong happens to classA or classB, I don't want to just lock the block of code. – Wenk Hsueh Dec 15 '17 at 03:13
  • 1
    `lock` lock on object. It does not care if that object stored in field of any other object or not. – user4003407 Dec 15 '17 at 03:26
  • Lock locks a block of code, not an object. What is your use case that locking blocks of code is unacceptable? – ProgrammingLlama Dec 15 '17 at 03:55
  • The [mono SynchronizedList code](https://github.com/mono/mono/blob/master/mcs/class/referencesource/mscorlib/system/collections/generic/list.cs#L1054-L1150) will probably help you understand `lock`. – ProgrammingLlama Dec 15 '17 at 04:18
  • @PetSerAl However, in order to access classB, I need to access classA first, does that mean classA need to be locked as well? – Wenk Hsueh Dec 15 '17 at 04:22
  • @Wenk You _do not_ lock classes. There isn't a language feature like that. – ProgrammingLlama Dec 15 '17 at 04:30
  • Locks only work if *everyone is playing by the same rules*. So it doesn't matter which object you lock on so long as everyone who is interacting agrees to lock the same object. If there's other code that isn't following any rules for accessing something that *should* be protected by a lock, then you cannot fix that problem without making changes to that other code. – Damien_The_Unbeliever Dec 15 '17 at 09:57

2 Answers2

3

Is containing class automatically locked if I lock its members, or it doesn't work like that at all.

It doesn't work like that at all. A lock does not do anything besides checking if the very same object reference is already locked, waiting until it's not and then locking it, removing the lock when the block is over. It does not imply anything else besides that one bit of information: is it locked or is it not.

Specifically, it does not lock any members, types or other things. It locks exactly the object you give. And a lock does not do anything except giving the information that a lock already exists if asked. It does not prevent code from accessing the object, reading, writing, Disposing, or whatever.

Your question reads a little bit like you expect a lock to have an effect besides interacting with other lock blocks. It does not.

So you should have a completely separate object to lock on, because bad things can happen if you use an object that is also used for another purpose and publicly available. As you gain nothing from using this or your class object, because lock does nothing extra, you really have nothing to gain from not following the best practice guidelines.

classA.classB is set and modified by codes I have no control of, those codes may be on different threads.

Now I want to modify classA.classB on the my thread.

You are f... rankly in a bad position. There is no solution to this. You cannot lock something that way. It's not one-sided. If the other code is not using the same lock you do... they won't care for your lock. A lock is like a signal. A red light. You can put a red light wherever you want, if the other driver does not know or does not care, there is nothing you can do.

Your only option would be to take control of the classB implementation and make sure it's thread-safe internally.

Community
  • 1
  • 1
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • @nviogt I get it now, Thanks! Every time I ask something simple and stupid I lose rep, that's um, interesting, this community is as helpful as it is toxic. – Wenk Hsueh Dec 15 '17 at 11:42
0

I think you are confused with the use of the lock statement. It makes sure that only one thread is inside one section of code and to do it, it uses something that can be signaled or not (consider it as a boolean).

lock(anobjectreference)
{
    .... code ....
}

Two threads that have the same anobjectreference cannot be inside the lock at the same time. anobjectreference is just an identifier based on the reference (pointer in memory) used to allow a thread to enter o not the lock.

There is a best practice that says that you should lock on objects created specifically to lock:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

In general, avoid locking on a public type, or instances beyond your code's control. The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:

  • lock (this) is a problem if the instance can be accessed publicly.

  • lock (typeof (MyType)) is a problem if MyType is publicly accessible.

  • lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.

Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.

Community
  • 1
  • 1
Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207