2011-05-27 37 views
8

我发布我对C#锁的理解如下,请帮助我验证我是否正确。C#锁关键字的用法

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

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

案例I>线程1和线程同时试图调用PrintOne。 由于PrintOne由实例锁保护,因此在任何时候,只有一个线程可以专门进入SectionOne。

这是正确的吗?

案例二>线程1和线程同时尝试分别拨打PrintOne和PrintTwo (即线程1调用PrintOne及线程调用PrintTwo) 由于两个打印方法是由同一个实例锁保护,在任何时候, 只有一个线程可以独占访问SectionOne或SectionTwo,但不能同时访问两者。

这是正确的吗?

+1

总结如下答案:代码是线程安全的仅为实例。当实例共享资源时,@oleski有正确答案(=否) – 2011-05-27 22:15:57

+0

因此-1不包含共享数据/资源。请编辑。 – 2011-05-27 22:21:19

+2

这是一个有效的观点,但最初的问题并没有说明这些实例是否是单独的,因此,从编写代码/问题的方式来看,假设他正在讨论针对同一实例进行的调用是安全的。所以,我不同意你的失望,但那是你的代表。 – 2011-05-27 22:43:21

回答

1

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

+0

代码是线程不安全的 – oleksii 2011-05-27 21:54:23

+0

@oleksii:就像你说的那样,只是每个实例都是安全的。然而OP写的关于实例锁。 – 2011-05-27 22:25:08

+0

我猜@亨克是有道理的,在这个特定的问题上,这个问题很模糊 – oleksii 2011-05-27 22:34:16

1

案例一:检查✓

案例二:检查✓

不要忘了锁是线程同步的一种方式。对于其他userfull方法,请阅读:Thread Synchronization

直接从MSDN样本:

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

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

我的建议:http://www.albahari.com/threading/ – 2011-05-27 21:25:22

+0

锁定对象不是静态的,代码是线程不安全 – oleksii 2011-05-27 21:55:29

+0

@Teoman请试试我的示例代码,你将得到一个IOException,文件用来。我相信这是一个有效的例子。锁定对象**必须是静态的。如果两个线程使用该类的不同实例,则会有两个锁定实例,并且该代码变为线程不安全。 – oleksii 2011-05-27 22:04:39

1

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

+0

+1 for _“允许分别进入两种方法,您希望有两个锁”_ – 2011-05-27 23:09:51

6

1和2 真的只有如果所有的线程使用类的相同实例。如果他们使用不同的实例,那么这两种情况

样品

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

UPDATE 好一点的konrad.kruczynski

做...... “线程安全” 也从 方面承担。例如,我可以采取 您的文件开放代码,并且 生成异常与静态锁 - 只需要另一个应用程序 域。因此建议OP 应该使用全系统互斥类或 这样的。因此,静态情况 只是推断为实例一。

+0

代码是线程安全的_per instance_。 OP提到“实例锁定”一次,但对实际共享的内容含糊不清。 – 2011-05-27 22:14:25

+0

@亨克我同意他提到实例锁定,将更新我的答案。 TNX。 – oleksii 2011-05-27 22:18:42

+3

锁性能与锁有多少争用非常直接相关。所以你真的不应该使用静态锁,除非你正在修改静态数据,并且如果你正在使用静态锁,除了保护静态数据外,你不应该使用静态锁。 – Yaur 2011-05-27 22:39:15

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

在此基础上你的代码是好的,如果你正在访问实例数据,但不安全的,如果你正在修改静态数据