我需要在我的代碼中進行數據同步。 目前我正在訪問中斷內部的全局值,並且在本地函數中,如果中斷調用頻繁可能會破壞數據。我需要避免這種情況。我沒有在我的代碼中使用操作系統,所以我不能使用信號量。使用與信號量類似的鎖定方法可能會解決我的問題。不使用semapore中的數據同步C
任何幫助,將不勝感激
我需要在我的代碼中進行數據同步。 目前我正在訪問中斷內部的全局值,並且在本地函數中,如果中斷調用頻繁可能會破壞數據。我需要避免這種情況。我沒有在我的代碼中使用操作系統,所以我不能使用信號量。使用與信號量類似的鎖定方法可能會解決我的問題。不使用semapore中的數據同步C
任何幫助,將不勝感激
中斷比線程或進程的工作方式不同 - 如果一個線程等待一個信號,它根本就沒有或計劃,直到信號燈變得可用,如果給定的等待超時時間。同時,可以安排其他線程,其中一個線程可能會回饋信號量。
中斷服務程序並不是這樣 - 它們不會被任何線程調度(如果有的話,只有其他中斷)中斷,而是被執行直到它們返回。所以如果一個ISR等待一個信號量(或者類似的機制,正如你所要求的那樣),那麼我們就處於一個死鎖狀態,因爲持有它的線程不能再被安排來給信號量返回......
所以你需要一個完全不同的機制!
通常的做法是禁用中斷,只要你的函數需要訪問公共數據,然後重新啓用它(你也可能需要在ISR本身內部完成)。
怎麼樣?那麼,操作系統/硬件的具體 - 只要你不提供進一步的細節,我在這裏...
只是一些提示呢:保持禁用中斷的時間儘可能短,並確保通常訪問的數據被聲明爲volatile!
這也可能是因爲這在主代碼一樣簡單:
disable_interrupts();
value += 1;
enable_interrupts();
所以你要確保當你在主代碼使用值中斷不能點火。
你需要的是對數據的原子訪問。如果它是一個單一的變量,你可以保證訪問是原子的,那就足夠了。但是,這涉及到反彙編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
不一定會導致內存障礙。在普通的微控制器上,它將工作得很好雖然)。
發佈您的代碼。 –
告訴我們關於您的硬件環境的一些信息。如果你有一個CPU核心和一個執行線程,最簡單的方法就是在你進行更新時禁用中斷。在多處理器環境中,處理器指令集通常會進行原子測試和設置指令或等效。 – JeremyP