Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (i.e. 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?

like image 323
q0987 Avatar asked May 27 '11 21:05

q0987


3 Answers

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.

like image 53
oleksii Avatar answered Sep 20 '22 15:09

oleksii


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.
        }
    }    
}
like image 23
Teoman Soygul Avatar answered Sep 19 '22 15:09

Teoman Soygul


Yes and yes. Cases are correct.

like image 28
konrad.kruczynski Avatar answered Sep 22 '22 15:09

konrad.kruczynski