在Lisp中执行期间的函数重新定义

弗尼夫尼

让我们假设我们有两个函数fct1fct2

  • fct1打电话fct2
  • fct1O1应用程序中的某些对象设置为状态A
  • fct2O2应用程序中的某些对象设置为state B

让我们假设以下约束必须始终成立:

  • 01处于A状态02且处于B状态),
  • XOR(01not(A)状态,并且02not(B)状态)。

如果会发生什么,在通话过程中fct1

  • 重新定义:fct1现在将一些对象01设置为state not(A)
  • 重新定义:fct2现在将一些对象02设置为状态not(B)

是否可以通过设置01为stateAstate02“打破”约束not(B)

我找到了这个答案:https : //stackoverflow.com/a/20477763/9614866

如果递归函数重新定义了自己,则仍将在同一调用中进行的递归调用可能会继续到达同一主体。一般而言,Common Lisp允许编译器在同一文件中的函数之间生成有效的调用。因此,您通常必须考虑将正在运行的代码替换为模块级别而不是单个功能级别。如果函数A和B在同一个模块中,并且A调用B,则如果仅替换B而没有替换A,则A可能会继续调用旧的B(因为B内联到A中,或者因为A没有通过A)符号,但对B使用更直接的地址。您可以声明为非内联函数以禁止这种情况。

我的问题是:

  • 会发生这种现象(即01设置为A状态并02设置为not(B)状态)?它有名字吗?

如是” :

  • 是否依赖于实现?
  • 有没有办法强制正确的行为,例如通过内联函数?
  • 我可以使用哪些工具来测试功能是否以正确的方式工作?测试似乎很痛苦:我不知道如何在不更改基本源代码的情况下测试重新定义。
  • 如何检测代码中可能出现此问题的部分?
核心转储

这是您描述的在多线程环境中如何发生的示例:

(progn

  (defun f2 (o2)
    (setf (car o2) :b))

  (defun f1 (o1 o2)
    (setf (car o1) :a)
    ;; the sleep here is to increase the risk of data-race
    (sleep 3)
    (f2 o2))

  ;; call the functions in a separate thread
  (sb-thread:make-thread
   (lambda () 
     (let ((o1 (list 0))
           (o2 (list 0)))
       (f1 o1 o2)
       (print (list o1 o2)))))

  ;; in parallel, redefine f2, then f1
  (defun f2 (o2)
    (setf (car o2) :not-b))

  (defun f1 (o1 o2)
    (setf (car o1) :not-a)
    (f2 o2)))

3秒后,REPL打印

((:A) (:NOT-B))

如果(declaim (inline f2))f2定义之前添加before并再次进行测试,则仍将从线程内的old f2来执行old 的代码,该代码f1将在3秒后显示以下内容:

((:A) (:B)) 

对该更新函数的进一步调用f1给出:

((:NOT-A) (:NOT-B)) 

我可以使用哪些工具来测试功能是否以正确的方式工作?测试似乎很痛苦:我不知道如何在不更改基本源代码的情况下测试重新定义。

也许您正在用新代码更新正在运行的服务器,并且希望避免在加载定义时让服务器使用部分函数重新定义。

与基础结构的所有其他方面一样,重要的是要预先计划如何可靠地进行备份和更新(数据库,配置等)。

一种可能的方法是逐包更新事物。您可以在软件包后缀版本号:

(in-package :web-0 ...)
(defun f2 () ...)
(defun f1 () ...)

;; new version
(in-package :web-1 ...)
(defun f2 () ...)
(defun f1 () ...)

当需要更新时,您可以编译和加载代码而:web-1不会干扰正在运行的代码。然后,您应该能够将调用者更改为使用新的实现:

;; somewhere in the main server package
(handle-request (request)
   (web-0:handle request))

 ;; update it
(handle-request (request)
  (web-1:handle request))

它甚至可以在没有版本号的情况下工作,如果您首先删除该软件包,然后使用相同的名称重新创建它,那么您将很难恢复。

某些地方可能还需要全局锁,您必须在应用程序中和更新期间都必须对此全局锁进行管理。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章