您需要禁用中斷以確保原子訪問。您不希望任何其他進程在您閱讀時訪問並可能修改該變量。
從Introduction to Embedded Computing:
原子訪問的需要
想象一下這樣的情景:前臺程序,在8位UC, 需要運行檢查一個16位的變量,稱之爲X 。因此它加載高字節,然後加載低字節(或者反過來, 命令無關緊要),然後檢查16位值。現在想象一下帶有相關ISR的 中斷,該中斷修改了這個16位變量。 進一步想象一下,在程序執行過程中給定的時間,變量的值碰巧是0x1234的 。這裏是非常糟糕的事情 可能發生:
- 前景負荷高字節(0×12)
- ISR發生時,修改X到0xABCD
- 前景負荷低字節(0XCD)
- 前臺程序見一個16位的0x12CD值。
的問題是,一個所謂不可分割一塊數據,我們 變量X,在訪問它, 因爲CPU的指令來訪問變量是除盡的過程實際上修改。 因此我們的變量X的負載已被破壞。你可以看到 變量的讀取順序無關緊要。如果在我們的示例中,訂單爲 ,則該變量將被錯誤地讀爲0xAB34而不是0x12CD,因此將 錯誤地讀取。無論哪種方式,讀取的值既不是 舊的有效值(0x1234)也不是新的有效值(0xABCD)。
編寫ISR參考數據並不好。這次假定 前臺程序爲了ISR的利益編寫了 先前的值0x1234,然後需要寫入新的值0xABCD。在 這種情況下,VBT如下:
- 前景存儲新高字節(是0xAB)
- ISR發生時,讀出X作爲0xAB34
- 前景存儲新低字節(0XCD)
代碼(這次是ISR)再次看到既沒有 有效值0x1234,也沒有看到新的有效值0xABCD,而是 的無效值0xAB34。
雖然spiTxRxByteCount &= ~0x0100;
看起來像C中的單個指令,但它實際上是對CPU的幾條指令。在GCC編譯時,彙編列表看起來像這樣:
57:atomic.c **** spiTxRxByteCount &= ~0x0100;
68 .loc 1 57 0
69 004d A1000000 movl _spiTxRxByteCount, %eax
69 00
70 0052 80E4FE andb $254, %ah
71 0055 A3000000 movl %eax, _spiTxRxByteCount
71 00
如果中斷是在兩者之間的任何這些指令並修改數據時,你的第一個ISR可以潛在讀取錯誤的值。因此,在對其進行操作之前,需要禁用中斷,並聲明變量volatile
。
如果你有一個RTOS,爲什麼不使用互斥鎖? –
@ [在OS下以這種方式實現的信號量操作](http://www.mpi-sws.org/~druschel/courses/os/lectures/proc4.pdf) –