2010-08-23 7 views
1

ApplicationException 생성자는 인스턴스 멤버이므로 스레드로부터 안전하지 않을 수 있습니다. 다음 코드가 완전히 불필요한 지 어떻게 알 수 있습니까? 내가 "알다"라고 말하면, 문서에 불필요하거나 .NET 소스 코드를 보았으므로 불필요하다는 것을 알리는 문서가 있습니다..NET 스레드 안전

// thread-safe 
internal static class TsApplicationException 
{ 
    private readonly static object myLock = new object(); 

    internal static void Throw(string msg, Exception e) 
    { 
     lock (myLock) 
     { 
      throw new ApplicationException(msg, e); 
     } 
     // the implementation of lock() ensures that the unlock will happen 
     // even if there is an exception thrown 
    } 
} 

편집 : 문서가 명시 적으로이 필요할 수 있습니다 제안하기 때문에이 문제는 근거없는 우려가 없습니다. 이 문제는 다소 퍼지는 문서 버그로 인해 발생할 수 있습니다.

편집 : 아래 코드는 내 스레드 이외에 직접적으로 책임이있는 코드와 내가 본 적이없는 코드를 제안했지만 아아아 나는 .NET의 클라이언트로 간접적으로 책임이 있습니다. Windows - 브라우저, 오피스, 뮤직 플레이어 등 내 컴퓨터에서 실행되는 스레드가 여러 개 있지만 제대로 작동하는 것 같습니다. 나는 이상적으로 내가보기에 다른 증거와 다른 것을 찾고 있다고 생각한다. 아마도 내 음악 플레이어를 쓴 사람들도이 방법으로 잠금을 설정하고 있습니다.)이 경우에는 전혀 증명할 수 없습니다.

이 문제에는 두 가지 변형이있을 수도 있습니다. 하나는 단일 응용 프로그램의 스레드 (.NET 및 Windows 스레드로 진행되는 작업)가 소리가 나는 문제이고 다른 하나는 모든 응용 프로그램의 스레드가 소리가 나는 것입니다 (서로 공존 함). .NET 및 Windows). 제 질문은 첫 번째 경우에 적용됩니다. Windows가 응용 프로그램을 격리 상태로 유지하는 방법에 대한 가정을하지 않으며이 질문을 게시하는 것과 관련하여 내 관심사가 아닙니다.

마지막으로,이 잠금이 필요한 경우 .NET Framework 및 타사 개체 사용을 위해 다른 많은 잠금이 필요합니다. 예 : MySQL 문서는 "thread-safe"가 보장되지 않은 인스턴스 메소드에 대해서도 같은 행을 가지고 있습니다. 여러 .NET 사례 및 대부분의 MySQL 사례에서 위험은 단순히 예외를 throw하는 것보다 훨씬 더 많은 기능을 포함합니다.

답변

2

ApplicationException 객체의 속성이 변경되지 않기 때문에 이는 필요하지 않으며 예외 객체의 모든 속성은 읽기 전용이라고 생각합니다.

따라서 스레드 안전성은 부적합합니다.

+0

ApplicationException 개체의 속성은 다른 스레드에서 변경하지 않지만 .NET 속성과 Windows 속성은 어떻게됩니까? – H2ONaCl

+0

".NET 속성 및 Windows 속성"이란 무엇입니까? 예외가 생성되면 핸들러에 도달 할 때까지 던져진 스레드의 스택을 넘기고 (또는 궁극적으로는 사용자에게 오류를 표시하는 핸들러 - 오브 - 그 전에 처리하지 못했습니다). 그 스레드에만 관련이없는 것은 아무 일도 일어나지 않습니다 (EventLog에 도달하면 로깅이 발생하지만 EventLog의 문제는 스레드로 처리되고 처리 할 수 ​​있습니다). –

+0

".NET 및 Windows 속성"이란 런타임 프레임 워크 및 운영 체제의 변수를 의미합니다. – H2ONaCl

4

첫째, 인스턴스 멤버 이 스레드 세이프 일 수 있습니다. 정적 멤버가 스레드 세이프이지만 이전에 논의한 이유로 인스턴스 멤버에 대해 동일한 보장을 제공하지 않도록하는 것이 일반적입니다.

둘째, 둘 이상의 스레드가 동일한 인스턴스에 액세스 할 수있는 컨텍스트에서 생성자가 호출되지 않습니다. 새로 생성 된 ApplicationException에 대한 유일한 참조는 그 시점에서 호출하는 메소드의 로컬이므로 하나의 스레드에서만 볼 수 있습니다. 두 스레드가 동시에 Throw 메서드에 충돌하면 두 개의 별도 인스턴스가 만들어집니다.

따라서 스레드 안전 자체가 아니지만 다중 스레드에서 액세스 할 수있는 컨텍스트에서는 사용되지 않으므로 잠금을 설정할 필요가 없습니다.

더 중요한 경우는 다음과 같습니다

이 코드에서
void MyFunctionOfThreadSafety(string someStr, int someInt, bool someBool) 
{ 
    if(someBool)// №1 
    { 
    var dict = new Dictionary<string, int>(); 
    dict[someStr] = someInt; // №2 
    int test = 0; 
    if(!dict.TryGetValue(someStr, out test))// №3 
     throw new Exception("really unexpected"); 
    dict[someStr] = test + someInt; // №4 
    } 
} 

이, 선이 №4을 통해 №1와 주석 장소가 어디에 문제의 객체가 어디에서 접근 하나 개 이상의 쓰레드에 의해, 다음 스레드 안전성 경우 문제는 문제를 일으킬 수 있습니다. (실제로, №1을 제외한 모든 스레드는 스레드가 전환 될 수 있고 이상한 것으로 시작하는 지점을 두 개 이상 제공합니다.)

이 코드는 전적으로 스레드로부터 안전합니다. 오브젝트로 잠재적으로 위험한 몇 가지 작업을 수행하고 있지만 그 오브젝트 중 하나만 다른 스레드가 변경할 수있는 것은 아닙니다.

someIntsomeBoolbyref 또는 out으로 전달되지 않은 값 유형 매개 변수입니다. 따라서이 메소드는 해당 메소드 (및 byref 또는 out에 전달할 때 호출하는 메소드)의 컨텍스트에서만 존재합니다.

someStr은 매개 변수로 전달되는 참조 유형이므로 잠재적으로 다른 스레드가 그 참조를받을 수있는 곳에 저장할 수도 있습니다. 그러나, 그것은 불변이므로, 스레드가 전혀 쓸 수 없으므로, 다른 스레드에 쓰는 위험이 없습니다. 읽기는 쓰기에서 보호 할 필요가 없습니다 (읽기 및 쓰기가있는 경우 읽기 및 쓰기를 모두 잠글 수도 있음). someStr에서만 읽기 작업이 가능하므로 안전합니다.

dicttest이이 메서드에서 만들어 지므로 안전합니다. 메서드에서 dict이 반환 된 경우 변경 가능한 참조 유형으로 여러 스레드에 표시되는 어딘가에 저장하면 스레드 안전 문제가 될 수 있습니다. 그러나 (a) 그것이 없었으며 (b) 이후에 까지는 문제가되지 않을 것입니다. 여기에 상관없이 스레드로부터 안전합니다.

+0

감사합니다. Jon, 나는이 점에 감사하지만 여기서는 내가 작성하지 않은 코드가 런타임 프레임 워크 또는 운영 체제 코드라는 것을 알 것입니다. – H2ONaCl

+0

당신은 누군가 다른 사람에게 메일을 보냈을 경우 메일 클라이언트, 귀하의 질문에 대한 예제를 작성하기위한 IDE, 어쩌면 윈앰프로 가서 몇몇 곡을들을 수 있도록 브라우저를 가동 할 것입니다. 그 동안 IM과 IM을 사용하여 동시에 친구와 연인과 채팅 할 수 있습니다.) 질문을 작성한 다음 페이지로 돌아가 응답을 읽습니다. 얼마나 많은 스레드가 관련되어 있는지 생각해보십시오. (저는 현재 4 코어 사이에 800 개가 넘습니다). 멀티 스레딩이 어려울 수 있지만 사람들은 올바르게 처리합니다. 우리에게 주어진 도구 세트의 부분은 ... –

+0

... 우리는 서로 다른 관심사 (이것은 다양한 레벨에서 발생하며이 외에도 다른 이유로 발생합니다)에 보관됩니다. 프레임 워크와 시스템이 실제로 나쁜 일을하지 않는 한 (자주 발생하지만 그렇게 자주하지는 않음) 의도적으로 엉망으로 만들지는 않습니다 (그리고 쉽지 않습니다). 자신 만의 것에 대해 걱정할 필요가 있습니다. 암호. –

0

생성자가 클래스에서 정적 데이터를 변경할 때만 스레드로부터 안전하지 않은 경우가 있습니다. 이것은 매우 드문 경우이므로 잠금이 필요하지 않습니다. 사실, 당신은 생성자의 사용법만을 잠그고 있으므로 TsApplicationException에서 실행되지 않는 다른 스레드는 ApplicationException을 동시에 던질 수 있습니다.

+0

예, 제가 제안한 것은 TsApplicationException.Throw의 보편적 인 사용법입니다. 답변 해 주셔서 감사합니다. – H2ONaCl

+1

구조체가 정적 데이터를 변경하고 스레드 안전성 자체를 처리하지 못하는 경우에는 문서화뿐만 아니라 양쪽 정렬이 필요한 것입니다 (즉, 그럴만 한 이유가 있다면 설명해주십시오. 생성자가 정말 나쁜 코드 인 것처럼 보일 것입니다.) –