Common Lisp:在独立线程调用类方法时出现无适用方法错误
问题分析与解决方案
核心错误原因
你遇到的SB-PCL::NO-APPLICABLE-METHOD-ERROR本质是**gorun宏实现完全错误**:
- 宏在编译阶段就直接执行
bt:make-thread创建线程,而非生成代码让程序运行时创建线程,完全违背了宏的代码生成特性。 - 传递给目标函数的是未求值的符号(比如
PRINTCH),而非符号对应的channel实例,导致recive方法接收到的参数类型不匹配。
另外,recive方法中引用了channel类未定义的name和thread槽,后续也会触发运行时错误,需要一并修复。
修正步骤
1. 修复gorun宏
宏的作用是生成运行时执行的代码,必须用反引号(`)构建线程创建逻辑,确保参数被正确求值:
(defmacro gorun (f &rest args) `(bt:make-thread (lambda () (,f ,@args)) :name "gorun worker"))
如果需要支持接收&rest参数的函数,可使用apply版本:
(defmacro gorun (f &rest args) `(bt:make-thread (lambda () (apply ,f (list ,@args))) :name "gorun worker"))
2. 修复recive方法的槽错误
原方法引用了channel类不存在的name和thread槽,修改如下(若不需要自定义线程名,直接固定命名即可):
(defmethod recive ((self channel)) (let ((thread (bt:make-thread #'(lambda() (recive-loop self)) :name "recive-thread"))) (bt:join-thread thread)))
如果需要给channel添加名称属性,可扩展类定义:
(defclass channel () ((messages :initform '() :accessor messages :documentation "Messages in the channel") (lock :initform (bt:make-lock) :accessor lock :documentation "Lock to push/pop messages in the channel") (cv :initarg :cv :initform (bt:make-condition-variable) :accessor cv :documentation "Conditional variable to notify the channel of a new message") (name :initarg :name :initform "unnamed-channel" :accessor name :documentation "Name of the channel")))
此时recive方法可改为:
(defmethod recive ((self channel)) (with-slots (name) self (let ((thread (bt:make-thread #'(lambda() (recive-loop self)) :name (format nil "recive-thread-~a" name)))) (bt:join-thread thread))))
3. 验证修复
重新加载所有代码后,执行标准实例化与测试代码:
(defvar printch (make-instance 'channel)) (gorun printover printch)
此时线程会正确传递channel实例给recive方法,不会再出现方法不匹配的错误。
内容的提问来源于stack exchange,提问作者badadumTss
相关产品推荐
相关产品推荐

