2017-05-04 69 views
0

我需要在我的代碼中進行數據同步。 目前我正在訪問中斷內部的全局值,並且在本地函數中,如果中斷調用頻繁可能會破壞數據。我需要避免這種情況。我沒有在我的代碼中使用操作系統,所以我不能使用信號量。使用與信號量類似的鎖定方法可能會解決我的問題。不使用semapore中的數據同步C

任何幫助,將不勝感激

+1

發佈您的代碼。 –

+1

告訴我們關於您的硬件環境的一些信息。如果你有一個CPU核心和一個執行線程,最簡單的方法就是在你進行更新時禁用中斷。在多處理器環境中,處理器指令集通常會進行原子測試和設置指令或等效。 – JeremyP

回答

4

中斷比線程或進程的工作方式不同 - 如果一個線程等待一個信號,它根本就沒有或計劃,直到信號燈變得可用,如果給定的等待超時時間。同時,可以安排其他線程,其中一個線程可能會回饋信號量。

中斷服務程序並不是這樣 - 它們不會被任何線程調度(如果有的話,只有其他中斷)中斷,而是被執行直到它們返回。所以如果一個ISR等待一個信號量(或者類似的機制,正如你所要求的那樣),那麼我們就處於一個死鎖狀態,因爲持有它的線程不能再被安排來給信號量返回......

所以你需要一個完全不同的機制!

通常的做法是禁用中斷,只要你的函數需要訪問公共數據,然後重新啓用它(你也可能需要在ISR本身內部完成)。

怎麼樣?那麼,操作系統/硬件的具體 - 只要你不提供進一步的細節,我在這裏...

只是一些提示呢:保持禁用中斷的時間儘可能短,並確保通常訪問的數據被聲明爲volatile!

+1

無鎖數據結構也可以提供幫助! – unwind

+0

您不必等待永久循環來獲取信號量,也可以檢查它是否可用。否則,ISR將不得不丟棄該值或將其保存在緩衝區中。 – Lundin

1

這也可能是因爲這在主代碼一樣簡單:

disable_interrupts(); 
value += 1; 
enable_interrupts(); 

所以你要確保當你在主代碼使用值中斷不能點火。

+1

如果這些函數改變了全局中斷掩碼,那麼這不是一個好主意。理想情況下,您應該只禁用受影響的中斷。 – Lundin

+0

@Lundin問題中沒有足夠的信息來提供理想的答案。 –

+0

這個代碼可以禁用全局中斷掩碼,或者它不會 - 它不明確,並且與問題無關。在我使用過的幾個系統中,一個名爲'enable_interrupts()'的宏導致設置/清除全局中斷掩碼。除非您完全控制MCU中的所有中斷,否則這通常不是一個好主意。 – Lundin

1

你需要的是對數據的原子訪問。如果它是一個單一的變量,你可以保證訪問是原子的,那就足夠了。但是,這涉及到反彙編C代碼,並看看你最終結果如何。即使機器代碼以原子(單指令)結尾,它也不可移植。

如果你有一個支持C11的現代編譯器,你可以聲明共享變量爲_Atomic,這將解決這個問題。

另一種選擇是在調用者的變量訪問期間簡單地關閉特定的中斷。然而,這會干擾實時性能,並且可能會漏掉中斷。

通用的「最佳」解決方案可能是自己發明一個信號量。例如:

// volatile to prevent dangerous compiler optimizations; does not solve re-entrancy 
volatile uint32_t data; 
volatile bool guard; 

void ISR (void) 
{ 
    if(!guard) 
    { 
    data = SOME_REGISTER; 
    } 
} 

void main (void) 
{ 
    ... 
    guard = true; 
    uint32_t local = data; 
    guard = false; 
} 

在上述例子中沒有原子訪問在所有保證,即使不將guard變量。但是,它不再是必需的,因爲在main()即將讀取數據時,保證設置guard。如果在讀取期間中斷將會啓動,它不會破壞數據。

這個解決方案唯一的缺點是當你設置警衛時你將錯過更新data。如果這是一個問題,你將不得不實施某種形式的臨時存儲。 (注意,這段代碼並不會導致「內存障礙」,所以在複雜的多核處理器上,這種方法可能不起作用,並且volatile不一定會導致內存障礙。在普通的微控制器上,它將工作得很好雖然)。

+0

上述解決方案很好。我的實際情況是,我將ADC中斷的值保存在全局變量中,並將其更新爲另一個子函數內的局部變量。所以函數和中斷會被頻繁地調用;所以我們需要在中斷中設置和重置guard變量,並在本地變量嘗試訪問全局變量之前提供函數檢查。當局部變量試圖訪問全局變量並且中斷髮生的時間和全局變量的值被更新導致數據損壞時,問題就出現了。 – Navin

+0

@Navin中斷不能被調用者中斷,所以不需要在那裏設置防護。 (除非你有一個多核解決方案,第二個內核執行中斷。) – Lundin

+0

@Lundin非常全面的回答覆蓋所有的事情想想 –