简体   繁体   English

C# lock 关键字的使用

[英]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.我将我对 C# 锁的理解发布如下,请帮助我验证我是否正确。

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.案例 I> Thread1 和 Thread2 同时尝试调用 PrintOne。 Since PrintOne is guarded by the instance lock, at any time, only one thread can exclusively enter the SectionOne.由于 PrintOne 受到实例锁的保护,因此在任何时候,只有一个线程可以独占进入 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.案例二> Thread1 和 Thread2 同时尝试分别调用 PrintOne 和 PrintTwo(即 Thread1 调用 PrintOne 和 Thread2 调用 PrintTwo) 由于两个打印方法由同一个实例锁保护,因此在任何时候,只有一个线程可以独占访问 SectionOne 或 SectionTwo ,但不是两者兼而有之。

Is this correct?这个对吗?

1 and 2 are true only if all your threads use the same instance of the class. 1 和 2当您的所有线程都使用 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.一种可能的解决方案是将 static 关键字添加到锁定 object 声明和使用它的方法中。

private  static object threadLock = new object();

UPDATE Good point made by konrad.kruczynski更新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.例如,我可以获取您的文件打开代码并使用 static 锁生成异常 - 只是获取另一个应用程序域。 And therefore propose that OP should use system-wide Mutex class or sth like that.因此建议 OP 应该使用系统范围的 Mutex class 或类似的东西。 Therefore static case is just inferred as the instance one.因此 static 案例仅被推断为实例之一。

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对于其他 userfull 方法,请阅读:线程同步

Straight from MSDN sample:直接来自 MSDN 示例:

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

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

Your understanding is 100% correct.您的理解是 100% 正确的。 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 1) 对实例数据使用实例锁

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

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

2) use static locks for static data 2) 对 static 数据使用 static 锁

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 3) 如果您要保护 static 和实例数据,请使用单独的 static 和实例锁

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基于此,如果您正在访问实例数据,则您的代码很好,但如果您正在修改 static 数据,则不安全

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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