2012-09-11 3 views
0

나는 어떤 이유로 BackgroundWorker 교체를 구현하고있어, 나는 공용 속성 다음 구현해야한다 :공용 속성을 스레드로부터 보호하려면 어떻게해야합니까?

public bool CancellationPending { get; private set; } 
public bool IsBusy { get; private set; } 
public bool WorkerReportsProgress { get; set; } 
public bool WorkerSupportsCancellation { get; set; } 

난 당신이 그들이 BackgroundWorker에서 봉사 무슨 목적을 알고 확신합니다. 그래서 그들은 다른 스레드에 의해 접근/수정 될 수 있습니다. 다중 스레딩을 "보호"하는 방법에 대해 우려하고 있습니다. volatile으로 충분하다고 생각했지만 자동 속성에는 volatile을 적용 할 수 없습니다.

어떻게해야합니까? 이러한 속성에 대한 비공개 필드를 만들고이를 volatile이라고 선언해야합니까? 또는 각각 getset 블록 안에 lock을 넣어야합니까?

이것은 매우 일반적인 시나리오 작성 속성 (선호 자동 속성)이 스레드로부터 안전해야한다고 생각합니다. 이 예제에서는 모든 속성이 원자 유형입니다.

편집 :

내가 필요한 것을 명확히하기 위해 : 나는 모든 스레드가 항상 재산의 최신 값을 읽을 수 있는지 확인해야합니다. 이 참조 : https://stackoverflow.com/a/10797326/1081467

를 그래서 다시 volatile, 또는 lock 보내고, 또는 다른 것을 사용하여 당신에게 조언을 할 수 있습니다 .. 최대 - 투 - 읽기 (그래서에만 두 번째 문제는 남아, 자성이 보장 된 bool 속성을 사용하는 경우? 날짜 값), 어떻게 이것을 정확하게 풀 수 있습니까? 비 프리미티브 타입의 속성을 가질 때는 어떻습니까? 각각 getset 블록에 lock 초를 넣었습니까?

+0

'BackgroundWorker' 클래스를 사용할 수 없습니까? –

+1

각'get'과'set' 블록 안에'locki'ng을 사용하십시오. 또는 형식을 변경할 수 없게하십시오. 예를 들어,'CancellationPending'에는 문제가 없을 것 같습니다. – Oded

+1

이 문맥에서'thread safe'가 정확히 무엇을 의미합니까? – asawyer

답변

5

다음 구현을 생각해 냈습니다.

//========== Public properties ==================================================// 

public bool CancellationPending { get { return _cancellationPending; } private set { _cancellationPending = value; } } 

public bool IsBusy { get { return _isBusy; } private set { _isBusy = value; } } 

public bool WorkerReportsProgress { get { return _workerReportsProgress; } set { _workerReportsProgress = value; } } 

public bool WorkerSupportsCancellation { get { return _workerSupportsCancellation; } set { _workerSupportsCancellation = value; } } 

//========== Private fields ==================================================// 

private volatile bool _cancellationPending; 
private volatile bool _isBusy; 
private volatile bool _workerReportsProgress; 
private volatile bool _workerSupportsCancellation; 

추론 : 자성이 필드 유형 bool의 사실에 의해 보장되고, lock ING에 대한 그래서 필요가 없습니다 당신이 최적의 솔루션이라고 생각 여부를 언급 해주십시오. 이들을 volatile으로 만들면 다른 스레드가 수정 한 경우 모든 스레드가 현재 값 (캐시되지 않음)을 읽을 수 있습니다. 나는 이것이 volatile 키워드의 정확한 목적 (그리고 오직 유효한 사용)이라고 생각합니다, 맞습니까?

+0

속성에 대해 휘발성을 정의 할 수 없습니다. 기초가되는 분야가 중요합니다. –

+0

이 속성은 휘발성 효과를 보호합니다. 휘발성 물질 제거가 효과가있는 경우를 만들어보십시오. –

+0

틀렸어. 다음은 증명입니다 : –

3
public bool CancellationPending { get; private set; } 
public bool IsBusy { get; private set; } 
public bool WorkerReportsProgress { get; set; } 
public bool WorkerSupportsCancellation { get; set; } 

그래서 그들은 서로 다른 스레드

없음

에 의해 액세스/수정 될 수는 단지 CancellationPendingIsBusy에 아닌 다른 사람에게 적용됩니다.
그리고 그들은 모두 원자가가 보장되는 불린입니다. 원자력은 여기 충분하다.

원래 Backgroundworker의 모든 속성은 이 아니며은 스레드로부터 안전합니다.
this page 하단을 참조하십시오.

+0

감사의 편집을 보시기 바랍니다, 고마워요. –

+0

그랬습니까. 다시 말하지만, 당신은 아마 아무것도하지 말아야합니다. 위의 주석을 참조하십시오. –

+1

비록 원자 일지라도, 하나의 스레드로부터 액세스를 가정하는 컴파일러 최적화를 방지하기 위해서는 '휘발성'으로 후킹 필드를 표시해야합니다. –

0

간단한 방법은 스레드로부터 안전하도록하려는 각 속성에 대해 뮤텍스 개체를 만드는 것입니다. get 및 set 속성에서 Monitor.Enter (declaredObjectMutext) 및 Monitor.Exit (declaredObjectMutex)를 사용합니다. 끝나면 속성이 스레드로부터 안전 해집니다 (get 및 set 호출은 다른 스레드가 완료 될 때까지 호출을 차단합니다).

또 다른 옵션은 정수 및 bool의 스레드로부터 안전한 수정을 허용하는 인터록 된 클래스를 사용하는 것입니다. 속성과 함께 사용하고있는 모든 것, 쉬운 해결책입니다.

1

비록 내가 거기에 더 나은 옵션을 sony 언급 된 것처럼 anothe 스케줄러와 작업을 사용하여 같은 생각합니다.

이 경로에서 계속하려면 잠금 및 휘발성 필드가 아닌 volatile does not do what you think을 사용해야합니다.Oh and this guy said something about never making a volatile field...

휘발성 대신 액세스 특성에 따라 즐겨 사용하는 동기 기본 (잠금, Mutex, 연동, ReaderWriterLockSlim 등)을 사용할 수 있습니다.

관련 문제