2012-08-27 59 views
1

我正在編寫一個多線程應用程序,其中一部分代碼必須是線程安全的以便跟蹤任務編號。跟蹤多線程應用程序中的任務號

我有這樣的方法:

private void IncrementTaskNumber() { 
    Interlocked.Increment(ref _TaskNumber); 
} 

_TaskNumber是在同一個類中的私人詮釋。問題是,這會引發我一個「屬性,索引器或動態成員訪問可能不會作爲out或ref參數傳遞」異常。 爲了解決這個問題,我做的:

private void IncrementTaskNumber() { 
    int _taskNum = _TaskNumber; 
    Interlocked.Increment(ref _taskNum); 
    _TaskNumber = _taskNum; 
} 

這仍然是線程安全的?

+0

請顯示'_TaskNumber'的聲明。鑑於錯誤消息,它聽起來像它被定義爲類似'private int _TaskNumber {get;組; } - 是正確的嗎? –

+0

@Reed Copsey,yes private int _TaskNumber {get;設置;} – ThomasVestergaard

+0

你需要使用一個字段,而不是一個私人財產 - 請參閱我的答案瞭解詳情。 –

回答

3

_TaskNumber是同一個類中的一個私有int。

_TaskNumber必須是一個私人這個工作。您可能將其作爲私人財產。

把它定義爲:

private int _TaskNumber; 

,它會工作。

另請注意,您當前的解決方法引入了競爭條件 - 您通過使用臨時變量來實現擺脫原子增量,這首先破壞了使用Interlocked的目的。您需要直接增加字段。

+0

非常感謝。這是更容易預計:) – ThomasVestergaard

1

您在IncrementTaskNumber方法中似乎沒有鎖定機制。除非你只從一個地方打電話,否則它不是線程安全的。第一個實現是你想要做的,即使它可以工作也不會是因爲Interlocked.Increment(ref _TaskNumber);可能在第一次完成之前被第二次調用,並寫入ref參數。

編輯: 如果你想讓它線程安全的,你可以修改夜方法是這樣的:

private void IncrementTaskNumber() 
{ 
    lock (_TaskNumber) 
     _TaskNumber++; 
} 

編輯2:(您可能要考慮其他的解決方案,如果使用lock是你太costy應用程序)

+0

如果使用鎖執行一個增量每個任務太昂貴,你可能有更大的問題。 – Servy

+0

@Servy對於小型工作機構,鎖可能變得非常昂貴。在TPL中有大量的管道,以避免因爲這個原因而準確地鎖定... –

+0

@ReedCopsey如果這是在循環中經常需要做的事情,那麼我會同意,但因爲它只做了一次如果這是一個真正的問題,那麼每個任務可能意味着你有太多的工作單元太小。 – Servy

0

這絕對不是線程安全的。

private void IncrementTaskNumber() { 
    int _taskNum = _TaskNumber; 
    Interlocked.Increment(ref _taskNum); 
    _TaskNumber = _taskNum; 
} 

因爲執行序列的線程可能被中斷在這三個操作中的每一個之間。這將不起作用,除非你引入一個循環,如果本地值在此期間發生變化,則循環會不斷增加,但這基本上意味着你正在使用Interlocked.Increment重新實現Interlocked.Increment。 :)

只是要_TaskNumber一個成員變量,而不是一個屬性。