同步
原子操作的動機來自于在共享資源時需要同步兩個或多個實體。一個簡單的例子可能是基于多線程 RTOS 的系統中的兩個線程,這兩個線程都需要偶爾向它們共享的 UART 外圍設備發送消息。
在操作中,一個線程可能會獲得對 UART 的控制權并持有該控制權,直到其整個消息被發送。否則,如果另一個線程決定在第一個線程未完成時發送消息,這兩個線程可能會通過 UART 發送替代字符,從而導致控制臺端口出現一堆難以理解的亂碼。
為了解決這個問題,我們可以定義一個資源,就像單個內存位置一樣簡單,它包含一個指示 UART 是忙還是可用的數據字。假設這個位置的 0 表示 UART 空閑,而 1 表示它正在使用中。
當線程 1 有消息要發送時,它會讀取鎖定字。它看到它是 0,所以它寫一個 1 到這個位置。任何其他想要發送消息的線程都會發現這個鎖或信號量包含一個 1,并且會等到它被清除后再嘗試獲取資源以供自己使用。
如果檢查和設置鎖的過程被中斷,就會出現問題。
考慮以下情況:
任務 1 讀取鎖定字。
它找到包含零的單詞。
任務 1 由于更高優先級的任務或導致其暫停的中斷而停止。
當任務 1 被掛起時,任務 2 以更高的優先級運行。
任務 2 需要發送一條消息并讀取它發現包含零的鎖定字。
任務 1 將 1 寫入鎖定字,知道它現在擁有 UART 的唯一控制權,直到其消息被發送。
由于所需資源不可用,任務 2 釋放控制權。
任務 1 繼續運行,知道鎖包含 0,將 1 寫入鎖字。
現在,任務 1 和任務 2 都確定它們對 UART 資源具有獨特的控制權,并將交錯地向其發送字符,因為他們看到它在逐個字符的基礎上變得可用。
原子操作
解決這個問題需要一個原子操作,以確保檢查和設置鎖定字的完整事務在任何其他代理(即使具有更高優先級的代理)可以中斷正在進行的關鍵操作之前完成。
原子操作只是以一個不間斷的順序完成的操作。即使這是一個復雜的事件序列。
對原子操作的支持內置于 C11 及更高版本等語言標準中。但是,用于在機器指令級別和硬件級別實現這一點的實際機制必須存在于 CPU 的指令集架構 (ISA) 和系統硬件實現中,以確保正確操作。
在上述情況下,任務 1 必須完成所有測試和設置鎖的步驟,然后任何其他任務或實體才能訪問內存中的鎖字。
在單核系統中,這通常可以通過簡單地在讀取鎖定字之前禁用所有中斷并在寫入鎖定后重新啟用它們來確保。通過這種方式,不會發生中斷,因此不會導致內核在其測試和設置操作的中間搶占任務 1。
當然,在具有其他總線主控器的單核系統的情況下,例如 DMA 控制器和可以直接寫入內存的外圍設備,這可能會因這些其他總線主控器之一在錯誤的時間寫入鎖定值而被違反。但是,可以通過確保存儲鎖變量的內存不能被系統中的任何其他總線主控器訪問來防止這種情況發生。
多核復雜性
現在我們看看在同一個芯片上有多個計算元素的情況,比如多核芯片,其中使用內存鎖定來確保在不同內核上運行的線程也可以共享資源而不會相互破壞。
在這種情況下,我們無法阻止不同的總線主機訪問鎖定位置。這是因為鎖定位置是每個內核必須能夠讀取和設置的位置,以確保正確共享公共資源(如上述 UART)。
現在我們必須確保一個核心一旦啟動就可以完成其讀-修改-寫序列,在任何其他核心或總線主控器可以訪問正在設置鎖的內存位置之前。
在 Arm 架構的 8.1 版及更高版本中,為此添加了新的原子指令。我將把這個例子集中在新的指令上。一種這樣的指令是 LDADD 指令及其變體。該指令從內存中讀取一個值,將芯片上的一個寄存器中的值相加,然后將結果寫回內存,同時保持內存總線,直到整個操作完成。
這樣,系統可以保證沒有其他總線主控器可以修改內存中的值,從而使兩個主控器都認為他們擁有共享資源的所有權。
這段代碼完成后,處理器可以檢查讀取的值,以驗證它實際上是資源的唯一所有者,并且它的值對應于在操作開始之前可用的資源。
現實世界的影響
好消息是,如果您使用 RTOS 或操作系統在單核或多核線程環境中管理線程,這一切都在較低級別的系統代碼中得到處理。然而,了解底層指令集和內存硬件必須設計為支持這些鎖定機制以使這一切正常工作是有用的。如果這些機制設計不正確或被直接操縱寄存器誤用,多個內核可能會無意中同時控制打算在使用時獨占的資源。要調試這類情況,需要先進的多核調試功能,其中可以觀察和控制在系統中的多個內核上運行的代碼。
調試多核同步
多核調試器可以通過顯示在多個內核或線程上運行的程序來幫助查找同步問題,以及根據另一個內核上的斷點有選擇地停止和啟動內核的能力應該是確定這種機制問題的理想選擇。
在圖 1 中,我們可以在 IAR Embedded Workbench 中看到帶有 4 個 CPU 的 NXP i.MX 8。所有核心都可以單獨啟動和停止。
圖 1:每個內核獨立的調試器控制。(來源:IAR 系統)
圖 2 顯示了在不同 CPU 上運行的代碼中使用多個斷點并結合使用互斥鎖(Arm 提供的示例):_mutex_acquire() 和 _mutex_release(),設置標志以阻止所使用對象的在素數計算中。
圖 2:在單個內核中使用互斥鎖和斷點。(來源:IAR 系統)
最常見的錯誤之一是濫用或未使用交叉觸發接口 (CTI)。對于 Arm,CoreSight 交叉觸發接口 (CTI) 通過交叉觸發矩陣 (CTM) 連接到每個內核。CTI 使調試邏輯、ETM 跟蹤單元和 PMU 能夠相互交互并與其他 CoreSight 組件交互。這使得每個核心可以獨立地停止和重置。不得不操縱“自制”的 CTI 變通方法,手動控制和停止內核,也許動態使用宏是一項不可能完成的任務。默認情況下,這應該并且需要由來自探針(CTI 接口信號)和軟件調試端的良好調試器處理。圖 3 顯示了完全控制 CTI 的用例。
圖 3:使用交叉觸發接口 (CTI) 進行完全控制。(來源:IAR 系統)
一旦全部結合在一起,具有多核支持的調試器就可以在非對稱和對稱場景中控制內核,甚至可以組合在一起。圖 4 顯示了運行 4 個 Cortex-A53 和 1 個 Cortex-M4 的 NXP i.MX 8 設備。MCU 和 MPU 可以獨立停止、監控和控制。雖然所有 4 個 Cortex-A53 內核或單個內核都從主會話運行,但可以在 Cortex-M4 合作伙伴端設置斷點,并專注于可能正在運行整個設備的安全監視器的此應用程序。
圖 4:在配備 4 個 Cortex-A53 和 1 個 Cortex-M4 的 NXP i.MX 8 設備上運行的多核會話。(來源:IAR 系統)
在應用程序中使用并行性和并發性旨在更有效地使用可用內核。然而,它的代價是增加了應用程序的復雜性,以及如何將源代碼拆分成更小的部分以盡可能高效地運行。
概括
在單個芯片或系統中同步多個內核需要原子操作和執行這些操作的硬件。首次開發這種硬件/軟件組合時,支持多核調試和觀察的全功能調試器對于發現此類系統的問題至關重要。無法想象如何通過在整個代碼中使用 print 語句來實現相同的控制,并使所有內容完美同步。每個開發人員都應該得到一個可以處理多核并完全控制所有線程的調試解決方案。IAR Embedded Workbench 及其調試器功能提供了這樣一個工具,在開發和調試這些復雜系統時非常有用。
Aaron Bauch是IAR Systems的一名高級現場應用工程師,與美國東部和加拿大的客戶合作。Aaron 曾為英特爾、Analog Devices 和 Digital Equipment Corporation 等公司從事嵌入式系統和軟件方面的工作。他的設計涵蓋了廣泛的應用,包括醫療儀器、導航和銀行系統。Aaron 還以南新罕布什爾大學教授的身份教授了許多大學水平的課程,包括嵌入式系統設計。Bauch 先生擁有紐約州紐約市 The Cooper Union 的電氣工程學士學位和哥倫比亞大學的電氣工程碩士學位。
-
ARM
+關注
關注
134文章
9087瀏覽量
367398 -
uart
+關注
關注
22文章
1235瀏覽量
101355
發布評論請先 登錄
相關推薦
評論