2011-01-26 118 views
4

我有一个私有静态字段,用于同步(锁定)。现在我有两个我不想同时执行的功能。所以我这样做:C#线程和同步

public class Synchronization 
{ 
    private static object _lock = new object(); 

    public void MethodA() 
    { 
     lock (_lock) 
     { 
      Console.WriteLine("I shouldn't execute with MethodB"); 
     } 
    } 

    public void MethodB() 
    { 
     lock (_lock) 
     { 
      Console.WriteLine("I shouldn't execute with MethodA"); 
     } 
    } 
} 

我知道,锁定的对象将防止单一功能的并行执行,但将同样的工作,如果我使用在同时运行不同的方法相同的锁定对象?简单地说,放任何其他线程可以锁定另一个函数中已经锁定的对象?

+2

为什么不干脆自己试一试? – 2011-01-26 09:27:49

+3

另请注意,通过这种方式,您已经同步了该类的每个实例。如果你不想这样做,请删除锁对象的“静态”部分。 – 2011-01-26 09:30:08

+1

@Andreas MT理论与实践很难 - 这不是一个有用的建议。 – 2011-01-26 09:30:08

回答

5

一次只能有一个线程获取该锁,因此该状态对于单个锁实例上的所有线程都是唯一的。因此,在您的示例中,对于类Synchronization的所有实例,在任何给定时间只有一个方法体可能正在执行,因为您的锁是静态的。如果你想锁定每个类的实例,那么不要将该锁对象标记为静态。

您对同步的假设是正确的。

请注意,您应该将锁物体readonly标记为完全防水的解决方案。正如代码表示,将有可能为重新分配的锁定对象,因此打破锁定语义,如:

public class Synchronization 
{ 
    private static object _lock = new object(); 

    public void MethodA() 
    { 
     lock (_lock) 
     { 
      Console.WriteLine("I shouldn't execute with MethodB"); 
     } 
    } 

    public void MethodB() 
    { 
     //This shouldn't be allowed! 
     _lock = new object(); 

     lock (_lock) 
     { 
      Console.WriteLine("I shouldn't execute with MethodA"); 
     } 
    } 
} 

锁定对象应被标记为readonly,即:

private static readonly object _lock = new object(); 
1

你正在做的正确。您创建了两个不会同时输入的关键部分。

因此MethodA和MethodB不会同时处于“活动”状态。而且同时只有一个MethodA(和MethodB)处于活动状态。

这适用于您创建的所有对象。我的意思是:任何对象都只能有一个线程在MethodA或MethodB中。如果你想锁只发生在一个对象内,你可以使_lock对象不是静态的。

1

根据作为锁定目标的对象授予锁定,而不是发生lock语句的方法。所以在你的情况下,多线程可能会进入各种方法,但一次只能有一个线程能够执行lock语句中的任何代码。

1

首先,_lock不应该是静态的。或者你想让对象的多个实例互相锁定自己?其次,你应该在一个类中只有一个同步方法。更重要的是,你应该避免类中同步方法之间的依赖关系。否则,你有风险,你的方法的调用者会做错了,并得到意想不到的行为。

考虑,例如,此代码:

class Synchronized 
{ 
    object lockObj = new object(); 
    int counter = 100; 

    public void Decrement() 
    { 
     lock (this.lockObj) 
     { 
      this.counter--; 
     } 
    } 

    public int IsZero() 
    { 
     lock (this.lockObj) 
     { 
      return this.counter == 0; 
     } 
    } 
} 

现在是什么将一个共享同步实例吗?

使用方法如下

while (!synchronized.IsZero()) 
{ 
    synchronized.Decrement(); 
} 

现在线程1调用递减,计数器到达0,并立即线程2调用递减,因为它是在锁递减法,不IsZero方法等。计数器现在是-1,循环是无限的。

这并不是锁定机制被错误编程,而是调用者没有很好地使用它。如果你只在同步类上暴露了一个同步方法,你不会愚弄程序员盲目相信它是安全的。

应该是这样的:

class Synchronized 
{ 
    object lockObj = new object(); 
    int counter = 100; 

    public bool IfNotZeroDecrement() 
    { 
     lock (this.lockObj) 
     { 
      if (this.counter > 0) 
       this.counter--; 

      return this.counter > 0; 
     } 
    }  
} 

/// Usage: 
while (synchronized.IfZeroDecrement()) 
{ 
}