2010-04-04 5 views
1

몇 가지 속성이있는 클래스가 있습니다. 모든 값 업데이트시 모든 필드를 파일에 저장하는 Store 메서드가 호출됩니다.이 코드는 스레드로부터 안전한가요?

private int _Prop1; 
public int Prop1 { 
    get { 
     return _Prop1; 
    } 
    set { 
     _Prop1 = value; 
     Store(); 
    } 
} 

// more similar properties here... 

private XmlSerializer _Ser = new ...; 
private void Store() 
{ 
    lock (_Ser) { 
     using (FileStream fs = new ...) { 
      _Ser.Serialize (fs, this); 
     } 
    } 
} 

이 디자인은 스레드로부터 안전한가요?

(당신이 더 적절한 자막을 생각할 수있는 경우에, BTW, 편집 주시기 바랍니다.)

을 나는 스레드로부터 안전하다고 생각합니다. 속성이 여러 스레드에서 변경되면 값은 임의의 순서로 설정되고 원자 저장소는 임의의 순서로 발생하지만 결국에는 모든 속성이 최신 값을 갖게되고 결국에는 원자 저장소가 발생합니다. 파일이 최신인지 확인하십시오.

명확화 : 속성은 자주 설정하지 않지만 동시에 설정할 수 있습니다. 중요한 것은 대부분 유효한 파일을 만드는 것입니다.

스레드가 등록 정보 값과 관련하여 등록 정보를 변경하는 경우 다른 스레드와 동기화하려면 전체 객체를 잠 가야합니다. 이것은 기본적으로 열거 형에서 List의 잠금과 동일하며이 클래스의 책임이 아닙니다.

+0

각 속성 수정 후 변경 내용을 디스크에 저장하는 것은 너무 비효율적입니다. 한 번에 20 개의 속성을 변경하려면 어떻게해야합니까? –

+0

내부 구성 요소이므로 자주 변경되지 않는다는 것을 알고 있습니다. – mafu

+0

"결국 모든 속성은 최신 값을가집니다"; 읽은 값을 정의되지 않은 상태 (예 : 호환되지 않는 값을 갖는 두 개의 속성)로 남겨두고 무언가가 해당 저장소간에 파일을 읽을 수 있습니까? 상점 중 하나가 어떤 이유로 고장 나더라도 똑같은 일이 발생할 수 있습니다. –

답변

1

전화를 걸 수있는 코드가 충분하지 않습니다. 하지만 확실히 파일에 대한 쓰기 액세스를 직렬화하지 않으면 아무 일도 일어나지 않을 것입니다. 첫 번째 스레드가 여전히 파일을 쓰는 중일 경우 속성을 할당하는 두 번째 스레드가 IOException에 폭탄을 넣을 것입니다.

이와 같은 미세 잠금은 일반적으로 문제가됩니다. 클라이언트 코드가 클래스의 둘 이상의 속성을 변경하는 중일 수 있습니다. 예외가 발생하면 부분 업데이트가 발생하여 유효하지 않은 직렬화 된 상태가 포함 된 파일을 생성하고 읽을 때 문제가 발생할 수 있습니다. BeginUpdate(), EndUpdate() 쌍과 같은 것이 필요합니다.

+0

파일 – mafu

+0

두 번째 단락 정보 : 사실입니다. 그러나 모든 값이 변경 될 때까지 Store가 연기되지 않으면 본질적으로 클래스 자체에서이 문제를 설명 할 수 없습니다. 또한 구현할 방법이 확실하지 않습니다. 제 경우에는 필요하지 않습니다. – mafu

+1

@mafutrct : 예, 클라이언트 코드의 도움없이 클래스를 스레드로부터 안전하게 만들 수있는 경우는 거의 없습니다. 그래서 .NET 프레임 워크 클래스는 전적으로 클라이언트 코드를 그대로 유지합니다. 클라이언트가 여러 스레드에서 절대로 사용하지 않을 때 불필요한 잠금은 좋지 않습니다. 정확히 여기서 중요하지 않지만 속성 설정자는 이미 매우 느립니다. 안내를 위해 .NET ApplicationSettings 클래스를 살펴보면 명시적인 Save() 메서드가 있습니다. 그러나 "구해야 만합니다"상태를 추적합니다. –

5

다른 스레드에서 호출하는 내용에 따라 다릅니다.

동시에 다른 스레드에 속성을 설정하면 직렬화되는 동안 속성이 변경 될 수 있으므로 스레드로부터 안전하지 않습니다.

+0

예. 그렇다면 변경된 후에 다시 직렬화됩니다. – mafu

0

데이터가 특정 지점에서만 직렬화되도록하려면 일종의 Mutex를 사용하는 것이 좋을 것입니다. 업데이트가 변경되거나 변경 될 때처럼 할 수 있습니다.

다음 링크는 MSDN 웹 사이트에 간단한 예제로 이동합니다

희망이 당신을 위해 그것을 증명해야한다 : 경우

Mutex Example

+0

어떻게 그럴 수 있습니까? 뮤텍스에 익숙하지 않은데, OP 코드를 사용하여 짧은 예제를 제공 할 수 있습니까? 또한, 실제로 필요하지 않으면 이것이 과잉이라고 생각합니다. – mafu

+0

일부 샘플 코드 –

1

번호

당신이 속성 theirself을 동기화 할 이 코드는 '잠금'이 _Prop1 값이 아니기 때문에 스레드 안전성이 없지만 _Ser에만 적용됩니다. 실제로 스레드가 속성에 접근 할 때 속성은 다른 스레드에 의해 설정 될 수 있습니다.

심지어 직렬화 프로세스에서 실행중인 다른 스레드 (_Ser이 실행되는 동안 다른 스레드가 Prop1로 설정)에서 변경할 수있는 속성에 대한 _Ser 액세스.

이 코드는 실제로 여러 스레드에서 XmlSerialize _Ser 개체를 사용하지 못하도록합니다. 그것은 ... 당신이 얻을 싶은 경우


대답은 당신이 얻을하려는 작업에 기본적으로 달려있다.

+0

에 대한 링크를 추가했습니다. 속성의 백엔드 값 설정은 항상 원자 적입니다. 다른 스레드가 동일한 속성에 액세스하면 액세스를 동기화해야합니다 (뭔가를 열거하는 것처럼).이 클래스에서는이를 수행 할 수 없습니다. – mafu

+0

여러 스레드에서 속성을 설정 한 후에도 결국 저장되므로 XmlSerializer를 사용하면 그 이유를 알 수 없습니다. 너 잘못 먹었 니? – mafu

+0

아, 이제 알았어. 파일이 최신 값으로 다시 기록 될 때까지 파일이 잠깐 동안 불완전한 상태 일 수 있음을 의미합니다. 맞습니까? 사실입니다. 내 구체적인 경우에는 문제가되지 않지만 이것이 일반적인 경우에이 코드의 문제라고 생각합니다. – mafu

0

Prop1 속성을 여러 스레드에서 호출 할 수있는 경우 _Prop1 필드를 volatile으로 지정하십시오.MSDN에서

private volatile int _Prop1; 

,

휘발성 키워드는 필드가 여러하여 동일한 시간에 실행중인 스레드를 수정 될 수 있음을 나타냅니다. 휘발성이 인 필드는 단일 스레드로 액세스하는 컴파일러 컴파일러의 적용을받지 않습니다. 이렇게하면 의 최신 값이 항상 필드에 표시됩니다.

좋습니다. 다른 사람들이 말했듯이, 클래스가 직렬화되는 동안 _Prop1의 값은 다른 스레드에 의해 변경 될 수 있기 때문에 스레드 안전을 위해 게시 한 코드를 작성하지 않을 것입니다. 하지만 여러 스레드에서 읽고 쓸 수있는 필드가있는 경우 필드를 휘발성으로 표시하면 코드에 최신 값이 표시됩니다.

+1

이것이 어떤 식 으로든 어떻게 도움이되는지 이해할 수 없습니까? – mafu

+0

(편집 후) 죄송합니다. 아직받지 못했습니다. 나는 컴파일러가 스레드의 안전성에 영향을주는 방식으로 public int 속성에 대한 액세스를 최적화 할 수 있을지 의심 스럽다. – mafu

+1

@mafutrct : 그것은 읽기 스레드가 최신 값을 읽도록 도와줍니다. 아니면 적어도 그런 식으로 읽습니다. 휘발성은 실제로 그것보다 약간 미묘합니다. 변경 가능한 유형의 잠금 무료 스레딩은 웜의 끔찍한 원인 일 수 있습니다. ( –

0

속성 유형이 원 자성이 아니면 스레드가 안전하지 않습니다.

스레드 A의

간단한 예 및 B.

A: Prop1 = foo 
A: Store() 
A: ... store saves foo.Var1 
B: Prop1 = bar 
A: ... store saves bar.Var2 (instead of foo.Var2) 

데이터의 무결성이 손상 가능성. Int64와 같은 단순한 유형의 경우에도 이론적으로 문제가 발생할 수 있습니다.

다른 lock(_Ser)을 세터 내에 넣으면 도움이됩니다.

+0

속성 유형은 원자입니다. 가능한 경우 'lock (_Ser)'을 피하고 싶습니다. 예를 들어, 필자는 이것이 정확히 일어날 것이라고 생각합니다. 결국 작성된 값은 최신 값입니다. – mafu

+2

원자력! = 휘발성. 원자 적으로 저장되고 있다고해서 다른 스레드가 저장되는 새로운 값을 읽지는 않는다는 것을 의미하지는 않습니다. –

관련 문제