2012-09-11 66 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 ING,或其他任何你的建議。當使用bool性質原子性保證,所以只有第二個問題是左(讀上TO-:看到了嗎?日期值),那麼你如何正確解決這個問題?當你有非原始類型的屬性時呢?你是否在每個getset塊中放置lock

+0

你不能使用'BackgroundWorker'類嗎? –

+1

在每個'get'和'set'塊內使用'locki'ng。或者,讓你的類型不可變。例如,'CancellationPending'不太可能有問題。 – Oded

+1

在這種情況下,「線程安全」是什麼意思? – 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

即使它們是原子的,爲了防止假設來自單個線程的訪問的編譯器優化,標記後備字段爲「volatile」是必要的。 –

0

一個簡單的方法是爲每個想要線程安全的屬性設置互斥對象。在get和set屬性中,使用Monitor.Enter(declaredObjectMutext)和Monitor.Exit(declaredObjectMutex)。完成後,這將使你的屬性成爲線程安全的(所有調用get和set的操作都將阻塞調用,直到任何其他線程完成)。

另一個選擇是使用互鎖類,它允許線程安全地修改整數和布爾值。如果這就是你使用你的屬性,它是一個簡單的解決方案。