2011-06-14 6 views
21

대리자 멤버 변수가있는 클래스 인스턴스가 있고 여러 스레드가 해당 대리자를 호출하면 (장기 실행 메서드를 가리킨다 고 가정) 경합 문제가 있습니까?C# 대리자가 스레드로부터 안전합니까?

대리자를 잠글 필요가 있습니까? 아니면 각 스레드가 자체 호출 스택을 가져 오기 때문에 각 스레드가 대리자가 가리키는 메서드를 호출하는 것이 안전합니까?

답변

7

아니요 스레드로부터 안전하지 않으며 그렇습니다. 동시성을 직접 관리해야합니다. 직접 MulticastDelegate의 문서에서

+0

대리인에 대해 변경 될 수있는 내용은 무엇입니까? (귀하의 의견은 이벤트에 대해서는 올바르지 만 대리인에 대한 변경 사항은 알 수 없습니다.) –

+1

@ agent-j : 그것은 중요하지 않습니다. 기본 구현은 변경 될 수 있지만 현재 문서는 명시된 바와 같습니다. –

6

는 :

이러한 유형의 멤버 (Visual Basic의 경우 Shared) 모든 공용 static 스레드로부터 안전합니다. 모든 인스턴스 멤버가 스레드로부터 안전하다는 보장은 없습니다.

Delegate 클래스에는 동일한 정보가 들어 있으므로 사용자가 가지고 있습니다.

2

이벤트 수정은 스레드로부터 안전하지는 않지만 대리인을 호출하는 것은 중요합니다. 대리자는 변경할 수 없으므로 스레드로부터 안전합니다.

here에서 빌린 : CLR 통해 C# 리히터에서 멀티 스레드 클래스에서 이벤트 호출에 대해 몇 가지 미묘한 점을 지적한다 : 여기 MSDN Delegate class 발언 참조

대리자 체인은 불변이다; 새로운 체인이 만들어져 첫 번째 체인을 대체합니다. 구독자가없는 대리인 체인이 null입니다. 즉, (귀하의 이벤트가 공개 된 경우) 언제든지 null에서 null이 아닌 그 반대가 될 수 있습니다.

+2

"모든 인스턴스 멤버가 스레드 안전성을 보장하지 않습니다." - 귀하의 링크 – heisenberg

23

위임자의 호출과 관련하여 대답은 '예'입니다.

대리자 호출은 대리자가 불변이므로 스레드로부터 안전합니다. 그러나 먼저 대리자가 있는지 확인해야합니다. 이 검사에는 원하는 안전 수준에 따라 일부 동기화 메커니즘이 필요할 수 있습니다.

예를 들어, SomeDelegate이 null 체크와 호출 사이의 다른 스레드에 의해 null로 설정된 경우, 다음은 NullReferenceException을 던질 수 있습니다.

if (SomeDelegate != null) 
{  
    SomeDelegate(); 
} 

다음은 좀 더 안전합니다. 여기서 우리는 델리게이트가 불변이라는 사실을 이용합니다. 다른 스레드가 수정하더라도 SomeDelegate 코드는 성가신 것을 막기가 어렵습니다 NullReferenceException.

Action local = SomeDelegate; 
if (local != null) 
{ 
    local(); 
} 

그러나,이 SomeDelegate 다른 스레드에서 null이 아닌 값이 할당 된 경우 대리자가 실행되고 있지 결코 될 수 있습니다. 이것은 미묘한 메모리 장벽 문제와 관련이 있습니다. 다음은 가장 안전한 방법입니다. 대답이 아니오 대리자가 참조하는 방법의 실행에 대해서

Action local = Interlocked.CompareExchange(ref SomeDelegate, null, null); 
if (local != null) 
{ 
    local(); 
} 

.

동기화 메커니즘을 사용하여 스레드 안전 보장을 제공해야합니다.이는 CLR이 대리자 실행을 위해 스레드 안전 보장을 자동으로 제공하지 않기 때문입니다. 특히 공유 상태에 액세스하지 않는 경우 안전을 위해 동기화를 더 이상 요구하지 않을 수도 있습니다. 그러나 메소드가 공유 변수를 읽거나 쓰는 경우 다중 스레드에서 동시에 액세스하지 못하게하는 방}을 고려해야합니다.

+0

또는 간단하게 그것을'public 이벤트 SomeHandler MyEvent = {}'로 선언 할 수 있고 null이 아니게 보장됩니다. –

+1

@Ed : 이벤트에 대해서는 작동하지만'SomeDelegate = null'을 수행 할 수 있으므로 원시 대리자에게는 작동하지 않습니다. –

+0

네, 맞습니다. (잘못) 이벤트를 맡았습니다. –

관련 문제