在 LabVIEW 中要使用全域變數,最常見的方法是使用內建的 Global variable 或更具存取控制設計的 Functional global variable (FGV)。本文的主角 Single Element Queue (SEQ) 是以 queue 為基礎所設計的全域變數的存取方式,除了有 by reference 這個特色,另外 SEQ 也符合 LabVIEW 資料流中常見的「初始化」、「讀/寫」與「關閉」的設計概念。
SEQ 的核心精神是創造一個長度為 1 的 queue,要存取的變數的資料型態則在 Obtain Queue 時決定。若要更新變數,將 queue 中的舊內容清除後再 enqueue 新的即可;讀取時則是使用 Preview Queue Element 將變數讀取出來。儲存在 queue 中的變數是以 queue reference 方式來連結,屬於 call by reference 架構。
SEQ 參考程式與範例下載:https://github.com/show6114/LV-SEQ-in-variant
在下圖的 SEQ 範例中,包含 Initialize.vi、Set.vi、Get.vi 與 Close.vi 四個 VI,分別是「初始化」、「寫入」、「讀取」與「關閉」四個變數的操作。這之中 SEQ 的變數是以 variant 來儲存。好處是變數的資料型態較不受挶限(都會先轉成 variant 再傳遞),這一組 SEQ VI 也得以重複使用;缺點是讀取變數時要做 Variant To Data 的轉換(轉換成變數原本的資料型態)。
Variant To Data 對於大型資料的轉換效率極差。若要存取大型資料,可以將 queue 的資料型態直接固定,雖然這樣一來這組 VI 就會變成專用 VI。另外,對於 cluster 這種複合的資料,可以將變數存成 Type Def.,即使之後變數內容更變了也不會影響到現有程式中 Variant To Data 的轉換。
這邊要注意的是,SEQ 在 Initialize 的時候,包含一個「SEQ name」的設計(詳下圖),這是從 Obtain Queue VI 延伸出來的設計(VI 內部詳下、下圖)。只要在同一個 memory scope 底下,使用相同的 SEQ name 的 SEQ 都可以存取到同一個變數。

上圖中 Initialize.vi 包含了 created new? 的判斷,一旦找到了相同 SEQ name 的 queue 就不會 enqueue 變數的初始值(Variant/initial value)進去,讓現值得以保留。
前述 SEQ 中的 Get.vi 是使用 Preview Queue Element VI 來讀取值(下圖),而非與 enqueue 對應的 dequeue 操作,這是因為必需要保留現有值。因為 SEQ 的 queue 長度是 1,若使用 dequeue 就等於把 queue 清空了。

小結
SEQ 的概念非常簡單,自己寫也很容易。SEQ 的參考程式與詳細的使用方法可以從前述的連結下載。若有任何問題歡迎留言討論。
發表迴響