簡體   English   中英

避免在 LUA 中使用 rFSM 庫兩次加載相同的腳本

[英]Avoid loading the same script twice with rFSM library in LUA

問題描述

以下代碼是復制我遇到的問題的最小示例。 使用了 rFSM 庫,可以在這里找到: https ://github.com/kmarkus/rFSM

有三個 lua 腳本。 “main”,稱為runscript.lua ,它初始化並運行需要運行的狀態機 (SM),稱為mainTask.lua ,而后者又使用輔助狀態機subTask.lua

代碼流程如下。 我們在狀態機mainTask.lua內部啟動並立即進入Sim復合狀態,然后狀態evaluate 在那里,我們調用subTask.lua中的函數evaluateData並將局部變量var設置為false 在這個函數調用之后,我們再次進入mainTask.lua ,進行一次轉換並再次進入subTask.lua 在那里我們打印var的值。

同樣,示意性地: mainTask.lua -> subTask.lua -> mainTask.lua -> subTask.lua

我們期望var的值為false 然而,正如你所見,在mainTask.lua中,我們通過rfsm.load("subTask.lua"),加載了subTask.lua兩次。 這導致有兩個輔助 SM 實例,但我想要一個。

rfsm.load函數是

function load(file)
   local fsm = dofile(file)
   if not is_state(fsm) then
      error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
   end
   return fsm
end

代碼

runscript.lua

-- Set lua path to location of rFSM library
package.path = "/home/anfr/rFSM-master/?.lua;./?.lua";
require 'rfsm';
print('[runscript.lua] Before rfsm.load("mainTask.lua")')
fsm_ = rfsm.load("mainTask.lua")
print('[runscript.lua] Before rfsm.init(fsm_)')
fsm = rfsm.init(fsm_);
print('[runscript.lua] Before rfsm.run(fsm)')
rfsm.run(fsm);

mainTask.lua

local var = true;

return rfsm.state{

  Sim = rfsm.composite_state
  {
    evaluate = rfsm.state {
      entry=function()
        var = false;
        if (evaluateData(var)) then
          rfsm.send_events(fsm, "internal_EvaluateDone")
        end
      end,
    },

    sub = rfsm.load("subTask.lua"),

    rfsm.trans { 
      src='initial', 
      tgt='evaluate',
      effect=function()
        print('[mainTask.lua] initial -> evaluate')
      end,
    },
  
    rfsm.trans { 
      src='evaluate', 
      tgt='sub',
      events={'internal_EvaluateDone'},
      effect=function()
        print('[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"')
      end,
    },
  }, -- end of Sim
  
  Seq = rfsm.composite_state
  {
    entry=function()
      print('Entry Seq')
    end,

    exit=function()
      print('Exit Seq')
    end,
 
    Running = rfsm.composite_state
    {
      entry=function()
        print('Entry Running')
      end,
  
      exit=function()
        print('Exit Running')
      end,

      --sub_2 = sub,
      sub_2 = rfsm.load("subTask.lua"),

      rfsm.trans { 
        src='initial', 
        tgt='sub_2',
        effect=function()
          print('[Seq composite state] initial -> sub_2')
        end,
      },

    },

    rfsm.trans { 
      src='initial', 
      tgt='Running',
      effect=function()
        print('[Seq composite state] initial -> Running')
      end,
    },
  
  }, -- end of Seq
  
  rfsm.trans { 
    src='initial', 
    tgt='Sim',
    effect=function()
      print('[mainTask.lua] initial -> Sim')
    end,
  },

};

subTask.lua

print("--- start of subTask.lua ---")
local var = true;

function evaluateData(value)
  print("[subTask.lua] var before setting in evaluateData is " .. tostring(var));
  var = value;
  print("[subTask.lua] var after setting in evaluateData is " .. tostring(var))
  return true
end

return rfsm.state {

  execute = rfsm.state {
    entry=function()
      print('[subTask.lua] var inside execute is ' .. tostring(var))
    end,
  },

  rfsm.trans {
    src='initial', 
    tgt='execute',
    effect=function()
      print('[subTask.lua] initial -> execute')
    end,
  },

},

print("---   end of subTask.lua ---")

日志

下面的日志顯示,我們第二次進入輔助SM時,我們使用了var的值為true的第二個實例(我們不希望這樣)。

[runscript.lua] Before rfsm.load("mainTask.lua")
--- start of subTask.lua ---
---   end of subTask.lua ---
--- start of subTask.lua ---
---   end of subTask.lua ---
[runscript.lua] Before rfsm.init(fsm_)
[runscript.lua] Before rfsm.run(fsm)
[mainTask.lua] initial -> Sim
[mainTask.lua] initial -> evaluate
[subTask.lua] var before setting in evaluateData is true
[subTask.lua] var after setting in evaluateData is false
[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"
[subTask.lua] initial -> execute
[subTask.lua] var inside execute is true

嘗試解決方案

嘗試 1

這種嘗試實際上適用於我的本地示例(不是真實系統)並使用注釋行sub_2 = sub 所以想法是加載一次狀態機,這里簡單參考一下。 我想知道不同版本的LUA是否對此有影響。 在本地,我在系統 Lua 5.1 上有 Lua 5.2。

編輯

如果我只是在Seq復合狀態中添加另一個虛擬狀態,此嘗試將停止工作。 也不依賴 Lua 版本。

嘗試 2

實現第二個版本的load和使用require而不是dofile 然后在mainTask.lua的那兩個地方使用這個函數。

function load2(file)
   local fileWithoutExtension = file:gsub("%.lua", "")
   print(fileWithoutExtension)
   local fsm = require(fileWithoutExtension)
   if not is_state(fsm) then
      error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
   end
   return fsm
end

如果我運行它,我會得到:

[runscript.lua] Before rfsm.load("mainTask.lua")
subTask
--- start of subTask.lua ---
---   end of subTask.lua ---
subTask
[runscript.lua] Before rfsm.init(fsm_)
lua: /home/anfr/rFSM-master/rfsm.lua:483: bad argument #1 to 'find' (string expected, got table)
stack traceback:
    [C]: in function 'find'
    /home/anfr/rFSM-master/rfsm.lua:483: in function '__resolve_path'
    /home/anfr/rFSM-master/rfsm.lua:511: in function '__resolve_src'
    /home/anfr/rFSM-master/rfsm.lua:551: in function 'func'
    /home/anfr/rFSM-master/rfsm.lua:272: in function 'f'
    /home/anfr/rFSM-master/utils.lua:246: in function 'map'
    /home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
    /home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
    /home/anfr/rFSM-master/utils.lua:246: in function 'map'
    /home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
    /home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
    /home/anfr/rFSM-master/utils.lua:246: in function 'map'
    /home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
    /home/anfr/rFSM-master/rfsm.lua:283: in function 'mapfsm'
    /home/anfr/rFSM-master/rfsm.lua:554: in function 'resolve_trans'
    /home/anfr/rFSM-master/rfsm.lua:704: in function 'init'
    runscript.lua:9: in main chunk
    [C]: in ?

我不明白為什么我得到一個表格而不是一個字符串。 不幸的是,需要在 rFSM 庫代碼中導航以提供幫助,但我會很感激任何提示。

Ps:在subTask.lua中將變量var設為全局將給出正確的行為。 但是,我試圖避免兩次加載相同腳本的不必要開銷。

我想知道不同版本的LUA是否對此有影響

所有 Lua 版本都具有相同的對象引用分配語義。


如您所見,在 mainTask.lua 中,我們通過 rfsm.load("subTask.lua") 加載了 subTask.lua 兩次

當您使用require時,將返回相同的狀態對象。


我不明白為什么我得到一個表格而不是一個字符串

函數resolve_trans(fsm)將轉換的.src字段從字符串轉換為對象(表)。
當您第二次解析相同的轉換對象時,會引發錯誤,因為tr.src字段應為字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM