使用C#lock关键字

时间:2011-05-27 21:13:58

标签: c# multithreading locking

我发布了对C#lock的理解如下,请帮我验证是否正确。

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

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

案例I> Thread1和Thread2同时尝试调用PrintOne。 由于PrintOne在任何时候都只受到实例锁的保护 一个线程可以专门进入SectionOne。

这是对的吗?

案例II> Thread1和Thread2同时尝试调用PrintOne和PrintTwo 分别(即Thread1调用PrintOne和Thread2调用PrintTwo) 由于两个打印方法都被同一个实例锁保护,因此, 只有一个线程可以独占访问SectionOne或SectionTwo,但不能同时访问两者。

这是对的吗?

6 个答案:

答案 0 :(得分:6)

如果您的所有主题都使用相同的类实例,那么

1和2 仅为 。如果他们使用不同的实例,则两种情况都是 false

样品

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();
        }
    }
}

测试代码

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
    }
}

可能的解决方案之一是向锁定对象声明和使用它的方法添加静态关键字。

private  static object threadLock = new object();

<强>更新 konrad.kruczynski提出的好点

  

...也假设“线程安全”   上下文。例如,我可以采取   你的文件打开代码也是   使用静态锁生成异常 -   只是另外申请   域。因此提出OP   应该使用系统范围的Mutex类或   ......那样的。因此静态情况   只是推断为实例一。

答案 1 :(得分:1)

是的,是的。案件是正确的。

答案 2 :(得分:1)

案例I:检查✓

案例II:检查✓

不要忘记锁定只是线程同步的一种方式。对于其他用户满意的方法,请阅读:Thread Synchronization

直接来自MSDN样本:

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

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

答案 3 :(得分:1)

您的理解是100%正确的。因此,例如,如果您想允许分别进入两个方法,则需要有两个锁。

答案 4 :(得分:0)

是的,你在两个方面都是正确的。

答案 5 :(得分:0)

这里是基础知识(或多或少)

1)使用实例锁来获取实例数据

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

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

2)对静态数据使用静态锁

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

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

3)如果要保护静态和实例数据,请使用单独的静态和实例锁

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++;
        }
     }
}

基于此,如果您正在访问实例数据,则代码很好,但如果要修改静态数据,则代码不安全