我正在使用 SBCL 为一个研究项目编写脚本,这是我第一次尝试 SB-TREAHD。每个线程将多次调用外部 shell 命令,为此使用 sb-ext:run-program。
问题是,每当出现 ext:run-program 时,程序就会陷入死锁(我没有明确使用 mutex 之类的东西)。我尝试了一段时间,找不到任何解决方案。仍然可以使死锁发生的代码的简化版本如下:
(use-package :sb-thread)
;;; Global Settings
(defparameter *path-num* 4)
(defparameter *testing* nil)
(defparameter *training* nil)
(defparameter *shared-folder* "shared")
(defparameter *template* "template.conf")
(defparameter *pwd* (namestring (truename ".")))
;;; Utilities
(defmacro compose-file-name (&rest parts)
"compose a filename under current *pwd*"
`(concatenate 'string *pwd*
,@(mapcar (lambda (x) `(format nil "/~a" ,x))
parts)))
(defun run-command (command &optional args)
"run a shell comamnd and reflect the stdout on screen."
(let* ((process (sb-ext:run-program command args
:output :stream
:wait nil))
(output (sb-ext:process-output process)))
(loop for line = (read-line output nil)
while line do (format t "~a~%" line))))
(setf *testing* '("1" "2" "3" "4"))
(setf *training* '("5" "6" "7" "8"))
(defun gen-conf (path-id target labeled)
"Prepare the configuration file"
(format t "[~a]: ~a~%" path-id target)
(let ((current-dir (compose-file-name path-id)))
(run-command "/bin/cp" (list "-f" (compose-file-name *shared-folder* *template*)
(format nil "~a/Prediction.conf" current-dir)))
(with-open-file (*standard-output* (format nil "~a/Prediction.conf" current-dir)
:direction :output
:if-exists :append)
(format t "--estimate ~a~%" path-id))))
(defun first-iteration ()
(loop for i below 20
do (gen-conf (thread-name *current-thread*) (format nil "~a" i) (list "123" "456"))))
;;; main
(defun main ()
(let ((child-threads (loop for i below *path-num*
collect (make-thread
(lambda () (first-iteration))
:name (format nil "~a" i)))))
(loop for th in child-threads
do (join-thread th))))
(main)
在(main)中创建了4个线程,每个线程都将运行(第一次迭代),并且在(第一次迭代)中它调用(gen-conf)几次,这涉及到(sb-ext:run-program)和文件 I/O。
我认为死锁可能是由于错误地使用了 sb-thread,但仅通过查看 SBCL 手册我无法找到正确的方法。任何建议都会有所帮助。
顺便说一句,要运行程序,请获取http://pages.cs.wisc.edu/~breakds/thread.tar.gz,其中创建了所有必需的目录/文件。
谢谢!