2011-01-26 5 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

이유는 단순히 자신이 그것을 시도를 제공하지 :

이 같은해야 하는가? –

+3

또한이 방법으로 클래스의 모든 인스턴스를 동기화했습니다. 원하지 않으면 잠금 개체의 "정적"부분을 제거하십시오. –

+1

@Andreas MT 이론과 실습은 어렵습니다. 이것은 도움이되지 않습니다. –

답변

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

정적 잠금을 다루는 것처럼'주어진 인스턴스의'로'오직 하나의 메서드 본문 만 '을 향상시켜야합니다 : –

+0

'readonly' ... !!! 신과 같은! –

+0

@ Andreas 정적 잠금의 의미에 대해 자세히 설명했습니다. –

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

하나가 공유 동기화 된 인스턴스에 무엇을 할 것인가?그것은 씩 감소 방법,하지 IsZero 방법으로 잠금을 기다리고 있기 때문에

는 지금 감소시킵니다은 카운터가 0에 도착 즉시 2 호출 감소시킵니다 스레드 1 호출 스레드이

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

처럼 사용합니다. 카운터가 -1이되고 루프가 무한합니다.

잠금 메커니즘이 잘못 프로그래밍 된 것은 아니지만 호출자가 올바르게 사용하지 않았 음을 의미합니다. Synchronized 클래스에서 하나의 동기화 된 메서드 만 노출 한 경우 프로그래머가 안전하다고 맹목적으로 판단하는 것을 속일 수는 없습니다.

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()) 
{ 
} 
+0

클래스에서 한 가지 동기화 된 방법에 동의하지 않습니다. 귀하의 예제는 구현이 잘못되었습니다. 0보다 작게 줄일 수없는 것이 중요하다면 감소액을 감당해야합니다. – btlog

+1

@btlog이 간단한 예제에서는 분명하지만, 더 복잡한 시나리오에서는 그다지 명백하지 않을 수 있습니다. 코드의 사용자에게 모든 책임을 부쳐서는 안됩니다. 그렇지 않으면 나중에 디버그하기 어려운 심각한 문제가 발생할 수 있습니다. 그것을 안전하고 깨끗하게해라. 그러면 모두는 장래에 그것으로부터 이익을 얻을 것이다. –

+0

권장 사항 (및 기타) : http://blog.objectmentor.com/articles/2008/04/08/clean-code-whew "메소드 간 종속성으로 인해 동시 코드가 손상 될 수 있습니다" –