0

I'm working on a class that creates and manages multiple socket connections and which will be forwarding information received from the sockets to the main thread and vice-versa. Multi-threading where I'm passing so much information in and out is new to me (as is most things in C#), so I need a clarification on what exactly locks do.

When I lock a section of a method does it only ensure that no other thread can enter that section of code or does it actually prevent all the variables in that section of code from being modified by other threads no matter where they occur?

For example:

public class TestLock
{
    public volatile int a = 0;
    public volatile int b = 2;
    private object ALock = new Object();

    public TestLock() { }

    public void UnlockEdit(int atemp, int btemp)
    {
        a = atemp;
        b = btemp;
    }

    public void LockedEdit(int atemp, int btemp)
    {


        lock(ALock)
        {
            a = atemp;
            b = btemp;
        }
    }

    public int[] ReturnValues()
    {
        int[] ret = new int[2];

        lock (ALock)
        {
            ret[0] = a;
            ret[1] = b;
        }

        return ret;
    }

}

If thread A calls the LockedEdit method and reaches the lock just slightly before thread B comes into UnlockEdit. What happens? Will the lock prevent thread B from modifying a and b? And will it block? Or does the lock only apply to the one particular branch of code? Or should I apply the same lock object (ALock) to every single read and write method for the objects I want to modify and read from multiple threads?

Kristof U.
  • 1,098
  • 8
  • 17
ThisHandleNotInUse
  • 1,087
  • 1
  • 9
  • 22
  • This question might also help you: http://stackoverflow.com/questions/9621438/confusion-about-the-lock-statement-in-c-sharp/9621805#9621805 – Eric Lippert Feb 04 '14 at 19:20

3 Answers3

7

When I lock a section of a method does it only ensure that no other thread can enter that section of code or does it actually prevent all the variables in that section of code from being modified by other threads no matter where they occur?

This question is so complicated and ill-formed that it is impossible to answer. Let's rewrite it.

When I lock a section of a method does it ensure that no other thread can enter that section of code?

Yes. A more accurate way to state that however is to say: the locked section cannot be entered until the lock associated with the "monitor" object given to the lock statement is obtained. That lock may only be obtained by one thread at a time.

I note also that there are subtleties about how locks may be obtained in scenarios involving more advanced usages of the monitor, such as pulsing. Again, read the documentation carefully for a description of the exact semantics of the operations of a monitor.

When I lock a section of a method does it only ensure that no other thread can enter that section of code?

No. Taking a lock has other actions than merely ensuring mutual exclusion on a block. It introduces a memory barrier, for example.

does it actually prevent all the variables in that section of code from being modified by other threads no matter where they occur?

Certainly not!

Will the lock prevent thread B from modifying a and b?

You build a bathroom with a door with a lock on one side and one side open to the outside world. You lock the bathroom door. Does that seem like an effective way to ensure that only one person can squeeze the toothpaste at a time?

And will it block?

Will what block?

does the lock only apply to the one particular branch of code?

I can't make sense of this question.

should I apply the same "lock" object (ALock) to every single read and write method for the objects I want to modify and read from multiple threads?

Yes.

A question you did not ask but should have:

Should I be using shared-memory multithreading in the first place?

Probably not. It is extremely difficult even for experts to get it right. Were I doing socket programming I'd start by using async-await or the Task Parallel Library to manage my asynchrony, rather than partying on threads directly. Threads are a very low-level tool intended for experts; try to raise the level of abstraction several levels.

Eric Lippert
  • 612,321
  • 166
  • 1,175
  • 2,033
  • Sorry, I meant "does it _only_ prevent it from entering that section of code." For example, the same locking "object" being used for two locks. I do read the documentation, or I'd have a lot more questions on here than I do so far - sometimes the documentation is a little unclear for me. I don't really know what was confusing about the first question. Though I suppose the pronoun "they" meaning "the variables" was a little vague as it could have referred to "the threads." As for your toothpaste metaphor: I didn't know what the lock method did exactly. – ThisHandleNotInUse Feb 04 '14 at 06:07
  • @ThisHandleNotInUse: The answer to the first question as you wrote it is "no". How would that have been helpful to you? – Eric Lippert Feb 04 '14 at 06:09
  • 1
    "*Yes. Consider reading the documentation; that's what the documentation says.*" Except the documentation is incorrect and the correct answer is "no". Other threads *can* access that same section of code, for example, by entering that section of code taking a *different* lock. (For example, if what to lock is passed as parameter to the code.) – David Schwartz Feb 04 '14 at 06:19
  • @DavidSchwartz: the documentation states "code executing in other threads is blocked from obtaining the lock until the lock is released". If you believe you've found an error in the documentation then say *where* the error is and I will bring it to the attention of the documentation manager. – Eric Lippert Feb 04 '14 at 06:24
  • @DavidSchwartz: Moreover, it is reasonable to assume that the original poster is asking the question about *the code presented* which does not pass in a lock object as a parameter. – Eric Lippert Feb 04 '14 at 06:25
  • The question asked, "When I lock a section of a method does it ensure that no other thread can enter that section of code?" The correct answer to that is "no", it only prevents other threads from acquiring that same lock. (The documentation is really just misleading, suggesting that locks protect code, which they don't.) – David Schwartz Feb 04 '14 at 07:27
  • @DavidSchwartz: I see your point; in fact, I made it myself! http://stackoverflow.com/questions/9621438/confusion-about-the-lock-statement-in-c-sharp/9621805#9621805 – Eric Lippert Feb 04 '14 at 19:18
  • 1
    As I discovered above, my misunderstanding from the documentation was that a lock could only lock one method at a time which made me question what its functionality was and how it operated as it's relatively inconvenient to have to route all potential read and writes on a volatile object through only ONE block of code. When I came to understand that the lock locks its object directly, no matter whatever other lock uses the same object, it made much more sense as you can have multiple lock statements which lock the same object, allowing more than one kind of read/write access. – ThisHandleNotInUse Feb 05 '14 at 00:44
  • 1
    @ThisHandleNotInUse: Got it; that makes sense. Thanks for following up. It is helpful for me to understand how and why people misunderstand language features! FYI I will be writing an article on how locks work behind the scenes on the Coverity Development Testing Blog on February 12th, so if this subject interests you, check it out then. – Eric Lippert Feb 05 '14 at 00:49
1

The lock statement creates a critical section in your code. This prevents other threads from entering the code inside the lock statements brackets. Other threads basically wait until it is their turn to enter the section.

It does not prevent other threads from modifying variables in the class. For instance, TestLock.a and TestLock.b could be modified by a function inside the TestLock class that does not use the Lock(ALock) statement. ALso, since variables a and b are public they could be modified by code outside the class (on a separate thread).

Here is a good link to .NET Basic Threading:

FROM MSDN:

The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section. If another thread tries to enter a locked code, it will wait, block, until the object is released.

Here is an example of some code that keeps variables safe for multithreaded applications (Taken from the C# 3.0 cookbook):

    public static class SaferMemberAccess
        {

            private static int numericField = 1;
                 private static object syncObj = new object( );

            public static void IncrementNumericField( )
           {
                     lock(syncObj)              
                         {
                       ++numericField;
                     }
           }

            public static void ModifyNumericField(int newValue)
            {
                     lock(syncObj)             
                         {
                       numericField = newValue;
                     }
            }

            public static int ReadNumericField( )
            {
                     lock (syncObj)            
                         {
                       return (numericField);
                     }
            }
        }
Matt Johnson
  • 1,833
  • 15
  • 21
  • If I use the same "object" - like "ALock" in the above code - in two different Locks, will only one lock be active at a time? I.E. If Thread A has entered the lock in "LockedEdit" and Thread B calls "ReturnValues" will thread B wait for Thread A's lock to release? – ThisHandleNotInUse Feb 04 '14 at 05:55
  • 1
    Yes Thread B will wait for Thread A's to exit the lock from LockedEdit – Matt Johnson Feb 04 '14 at 06:00
  • Thank you very much - that was pretty much the connection I wasn't making because I was trying to figure out how I would modify and/or read the same object in different ways if I could only lock one method at a time to modify it. – ThisHandleNotInUse Feb 04 '14 at 06:11
1

You acquire a lock on the object as you did here

lock(ALock)

this section of the code is now locked by this object and no other object can get in until the lock is freed, i.e this object leaves the critical section.

It also means that in this time no other object will be able to modify the variables locked by this object in the critical section.

Prince
  • 18,883
  • 5
  • 34
  • 54