简体   繁体   中英

Usage of the C# lock keyword

I post my understanding of C# lock as follows, please help me validate whether or not I get it right.

public class TestLock
{
    private object threadLock = new object();
    ...
    public void PrintOne()
    {
        lock (threadLock)
        {
            // SectionOne
        }
    }

    public void PrintTwo()
    {
        lock (threadLock)
        {
            // SectionTwo
        }
    }
    ...
}

Case I> Thread1 and Thread2 simultaneously try to call PrintOne. Since PrintOne is guarded by the instance lock, at any time, only one thread can exclusively enter the SectionOne.

Is this correct?

Case II> Thread1 and Thread2 simultaneously try to call PrintOne and PrintTwo respectively (ie Thread1 calls PrintOne and Thread2 calls PrintTwo) Since two print methods are guarded by the same instance lock, at any time, only one thread can exclusively access either SectionOne or SectionTwo, but NOT both.

Is this correct?

1 and 2 are true only if all your threads use the same instance of the class. If they use different instances , then both cases are false

Sample

public class TestLock
{
    private  object threadLock = new object();

    public void PrintOne()
    {
        lock (threadLock)
        {
            Console.WriteLine("One");
            var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource
            f.Close();
        }
    }

    public void PrintTwo()
    {
        lock (threadLock)
        {
            Console.WriteLine("Two");
            var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource
            f.Close();
        }
    }
}

And testing code

static void Main(string[] args)
{
    int caseNumber = 100;

    var threads = new Thread[caseNumber];
    for (int i = 0; i < caseNumber; i++)
    {
        var t = new Thread(() =>
                                {
                                    //create new instance
                                    var testLock = new TestLock();
                                    //for this instance we safe
                                    testLock.PrintOne();
                                    testLock.PrintTwo();
                                });
        t.Start();
        //once created more than one thread, we are unsafe
    }
}

One of the possible solutions is to add a static keyword to the locking object declaration and methods that use it.

private  static object threadLock = new object();

UPDATE Good point made by konrad.kruczynski

..."thread safety" is also assumed from context. For example, I could take your file opening code and also generate exception with static lock - just taking another application domain. And therefore propose that OP should use system-wide Mutex class or sth like that. Therefore static case is just inferred as the instance one.

Yes and yes. Cases are correct.

Case I: Check ✓

Case II: Check ✓

Don't forget that locking is only one way of thread synchronization. For other userfull methods, read: Thread Synchronization

Straight from MSDN sample:

public class TestThreading
{
    private System.Object lockThis = new System.Object();

    public void Process()
    {    
        lock (lockThis)
        {
            // Access thread-sensitive resources.
        }
    }    
}

Your understanding is 100% correct. So if, for instance, you wanted to allow entry into the two methods separately you would want to have two locks.

Yes, you're correct in both counts.

here are the basics (more or less)

1) use instance locks for instance data

public class InstanceOnlyClass{
    private int callCount;
    private object lockObject = new object();

    public void CallMe()
    {
        lock(lockObject)
        {
            callCount++;
        }
     }
}

2) use static locks for static data

public class StaticOnlyClass{
    private int createdObjects;
    private static object staticLockObject = new object();

    public StaticOnlyClass()
    {
        lock(staticLockObject)
        {
            createdObjects++;
        }
    }
}

3) if you are protecting static and instance data use separate static and instance locks

public class StaticAndInstanceClass{
    private int createdObjects;

    private static object staticLockObject = new object();

    private int callCount;

    private object lockObject = new object();

    public StaticAndInstanceClass()
    {
        lock(staticLockObject)
        {
            createdObjects++;
        }
    }

    public void CallMe()
    {
        lock(lockObject)
        {
            callCount++;
        }
     }
}

based on this your code is fine if you are accessing instance data but unsafe if you are modifying static data

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM