7

如何在 ABCL 中生成背景(命名)子进程/线程?也就是说,我想生成子进程(或线程)以在后台运行,并将顶级评估留给其他处理。

使用 (apropos 'process/thread) 我发现了像下面列出的那些未记录的函数,但我无法弄清楚语法。我正在寻找要遵循/修改的运行示例代码。我似乎已经使用以下 make-process 函数创建了一个进程,但是当我尝试杀死它时出现错误,它在前台运行。ABCL 手册中没有关于 make-process 的条目。列出了 MAKE-THREAD,但未记录

ABCL 手册中列出的带有“未记录”名称的所有功能的文档/示例在哪里?(还有那些恰到好处的发现?)

作为一个单独但相关的问题,是否有一个在线的 ABCL 特定运行代码示例存储库,涵盖了此类边缘案例问题?

在其他 common-lisps 中,我会使用如下函数:

(activate-process *initial-process*)

或者

#+(:and MULTITASKING :lucid)
(defun mpd (&optional (reinit nil))
  (user::make-process :name "Pdraw-proc" :function #'pd::pdraw :args (list reinit)))

在 ABCL 中,我糊里糊涂地走得不远:

CL-USER> (setf uu (make-thread (my-reader))) <-- runs at the top level / hogs read loop

CL-USER> (setf jj (system::%make-process (foo)))
#S(SYSTEM:PROCESS :JPROCESS 3 :INPUT NIL :OUTPUT NIL :ERROR NIL)
CL-USER> jj
#S(SYSTEM:PROCESS :JPROCESS 3 :INPUT NIL :OUTPUT NIL :ERROR NIL)


SYSTEM::MAKE-PROCESS (fbound)
SYSTEM::%PROCESS-KILL (fbound)
SYSTEM::%MAKE-PROCESS (fbound)

THREADS:MAKE-THREAD (fbound)
THREADS:DESTROY-THREAD (fbound)

(make-two-way-stream ...) 

[可能为线程创建必要流的语法/示例?]

提前感谢您的指针或代码。

4

2 回答 2

4

我将 ABCL 与roswell一起使用,因此它很容易与 quicklisp 结合使用,但也有一个项目但我认为您可以轻松地使用 quicklisp 或在 ABCL 中加载库。您可以在 ABCL 上加载很多来自 quicklisp 的库,不幸的是不是全部(Quicklisp 在 linux 和 SBCL 上进行了测试),但是对于并发性,您可以加载两个我通常使用bordeaux-threads的优秀库(常见的威胁library in common lisp) 和Chanl是一个将通道移植到 common lisp 的库。您可以尝试其他一些方法,但我不确定它们是否可以并行工作,cl-actors ...

让我们用这个库做一个例子:

CL-USER> (lisp-implementation-type)
"Armed Bear Common Lisp"
CL-USER> (lisp-implementation-version)
"1.5.0"
"Java_HotSpot(TM)_64-Bit_Server_VM-Oracle_Corporation-1.8.0_162-b12"
"x86_64-Mac_OS_X-10.12.6"

CL-USER> (ql:quickload 'bt-semaphore)
To load "bt-semaphore":
  Load 1 ASDF system:
    bt-semaphore
; Loading "bt-semaphore"
[package bt-semaphore]
(BT-SEMAPHORE)
CL-USER> bt:*supports-threads-p*
T

CL-USER> (defparameter *counter* 0)
*COUNTER*
CL-USER> (defun test-update-global-variable ()
  (bt:make-thread
   (lambda ()
     (sleep 10)
     (incf *counter*)))
  *counter*)
TEST-UPDATE-GLOBAL-VARIABLE
CL-USER> *counter*
0 (0 bits, #x0, #o0, #b0)
CL-USER> (test-update-global-variable)
0 (0 bits, #x0, #o0, #b0)
CL-USER> *counter*
0 (0 bits, #x0, #o0, #b0)
CL-USER> (+ 2 3)
5 (3 bits, #x5, #o5, #b101)
CL-USER> (format t "I'm wainting for counter")
I'm wainting for counter
NIL
CL-USER> (format t "let'see the counter value ~a~%" *counter*)
let'see the counter value 1
NIL

CL-USER> (ql:quickload :chanl)
To load "chanl":
  Load 1 ASDF system:
    chanl
; Loading "chanl"

(:CHANL)

CL-USER> (chanl:pcall (lambda () (sleep 10) (incf *counter*)))
#<CHANL:TASK Anonymous task [ALIVE] {2360938E}>
CL-USER> *counter*
1 (1 bit, #x1, #o1, #b1)
CL-USER> ;; waiting
; No values
CL-USER> *counter*
2 (2 bits, #x2, #o2, #b10)

请注意,这只是示例,全局变量不能很好地用于威胁,还请查看库以获取更多文档,这应该可以工作,而且您在 ABCL 中很容易使用 java 库,所以也许您可以使用akka actor,或其他 java 并发库

此外,正如您指出 ABCL 有一个威胁包,它很容易使用,如下所示:

CL-USER> (threads:make-thread (lambda () (sleep 10) (incf *counter*)) :name 'patata)
#<THREAD "PATATA" {49998577}>
CL-USER> *counter*
2 (2 bits, #x2, #o2, #b10)
CL-USER> ; wait
; No values
CL-USER> *counter*
3 (2 bits, #x3, #o3, #b11)

它还实现了邮箱威胁以将消息传递给线程

于 2018-05-16T08:54:59.807 回答
0

在 Vibhu 的提示下,我发现似乎与 Anquegi 建议的本地解决方案相同。感谢 :name 参数!

CL-USER> (lisp-implementation-type)
"Armed Bear Common Lisp"
CL-USER> (lisp-implementation-version)
"1.3.3"
"Java_HotSpot(TM)_64-Bit_Server_VM-Oracle_Corporation-1.8.0_161-b12"
"amd64-Windows_7-6.1"
CL-USER> 


(setf my-val 1)

;;; Output to *standard-output* for Inferior Lisp, so careful with SLIME:
(defun make-my-thread ()
  (setf q
    (threads:make-thread
     #'(lambda ()
         (format t "I am alive!~%")
         (sleep 15)
         (format t "Goodbye Cruel World~%")
       (setf my-val (1+ my-val))))))


;;; Works, but takes a while: 
(defun kill-it () (threads:destroy-thread q))

(defun alivep () (THREADS:THREAD-ALIVE-P q))

(make-my-thread) 在后台运行而不占用标准输入

my-val可以被查询,直到睡眠后才设置。

(alivep) 返回 T 直到线程完成或调用 (kill-it) 几秒钟后,然后返回 NIL。

所以这个最小的功能现在允许我在后台运行线程有很大的灵活性。

于 2018-05-17T06:55:00.393 回答