WITH-OUTPUT-TO-STRING with multithreading in Common Lisp - multithreading

I want to do something that means the following:
(with-output-to-string (*standard-output*)
(bt:join-thread
(bt:make-thread
(lambda ()
(format *standard-output* "Hello World")))))
;=> "" (actual output)
;=> "Hello World" (expected output)
In my understanding, this does not work because the *standard-output* that gets dynamically rebound by with-output-to-string outside the thread does not take effect inside the thread. What are the possible and recommedable ways?
In essence, I want to capture the output that was written to *standard-output* by another thread.

One can rebind the special variable to be thread local:
(with-output-to-string (*standard-output*)
(bt:join-thread
(bt:make-thread
(lambda ()
(format *standard-output* "Hello World"))
:initial-bindings `((*standard-output* . ,*standard-output*)))))
*initial-bindings* is an alist with (variable . value) elements.

A previous idea was to mutate the original binding of *standard-output* itself. As #coredump suggested, this has the downside that the binding will be mutated in all the threads - other threads that are sending their output to *standard-output* would also send their output to the string-output-stream.
Another idea is to let the thread itself decide whether to send the output to *standard-output* or to some other stream:
(let ((in-with-output-to-string nil)
(output-stream-string nil))
(unwind-protect
(progn
(setq output-stream-string (make-string-output-stream))
(setq in-with-output-to-string t)
(bt:join-thread
(bt:make-thread
(lambda ()
(format (if in-with-output-to-string
output-stream-string
*standard-output*)
"Hello World"))))
(get-output-stream-string output-stream-string))
(setq in-with-output-to-string nil)))
;=> "Hello World"
A more involved example is illustrated in the following. The general situation I was interested in involved a thread reading some stream and sending the contents of that stream to *standard-output*. However, in certain cases, I was interested in capturing the output of that thread into a string.
Even before that, drawing inspiration from [1], we define a helper macro which captures the variable bindings that were present before executing the body and then restores them once the body has completed execution.
(deftype list-of (&rest types)
(if types
`(cons ,(first types) (list-of ,#(rest types)))
'null))
(defmacro thread-global-let (bindings &body body)
(let* ((bindings (mapcar (lambda (binding)
;; Normalize the bindings
(etypecase binding
(symbol
(list binding nil))
((list-of symbol)
(list (first binding) nil))
((list-of symbol t)
binding)))
bindings))
(variables (mapcar #'first bindings))
(gensyms (alexandria:make-gensym-list (length variables))))
`(let (,#(mapcar (lambda (var gensym)
`(,gensym ,var))
variables gensyms))
(unwind-protect
(progn
,#(mapcar (lambda (binding)
`(setq ,#binding))
bindings)
,#body)
,#(mapcar (lambda (var gensym)
`(setq ,var ,gensym))
variables gensyms)))))
The main example then is the following:
(defvar *input-wait-condition* (bt:make-condition-variable))
(defvar *input-wait-lock* (bt:make-lock))
(defvar *stream-input-string* nil)
(defvar *thread*)
(let ((in-with-thread-output nil)
(stream-output-string nil))
(when (and (boundp '*thread*)
(bt:threadp *thread*))
(bt:destroy-thread *thread*))
(setq *thread*
(bt:make-thread
(lambda ()
(bt:with-lock-held (*input-wait-lock*)
(loop :do (bt:condition-wait *input-wait-condition* *input-wait-lock*)
(loop :while (listen *stream-input-string*)
:do (write-char (read-char *stream-input-string*)
(if in-with-thread-output
stream-output-string
*standard-output*))))))))
(defun thread-output-thunk (thunk)
(thread-global-let ((stream-output-string (make-string-output-stream))
(in-with-thread-output t))
(funcall thunk)
(get-output-stream-string stream-output-string))))
(defmacro with-thread-output (&body body)
`(thread-output-thunk (lambda () ,#body)))
What it essentially achieves is the following:
CL-USER> (setq *stream-input-string* (make-string-input-stream "Hello World"))
#<SB-IMPL::STRING-INPUT-STREAM {100D0D47A3}>
CL-USER> (bt:condition-notify *input-wait-condition*)
NIL
Hello World
CL-USER> (with-thread-output
(thread-global-let
((*stream-input-string*
(make-string-input-stream "Output from a thread")))
(bt:condition-notify *input-wait-condition*)
(loop :while (listen *stream-input-string*))))
"Output from a thread"
CL-USER> (with-thread-output
(thread-global-let
((*stream-input-string*
(make-string-input-stream "Output from a thread")))
(print (with-thread-output
(thread-global-let
((*stream-input-string*
(make-string-input-stream "Output from a thread 2")))
(bt:with-lock-held (*input-wait-lock*)
(bt:condition-notify *input-wait-condition*))
(loop :while (listen *stream-input-string*)))))
(bt:with-lock-held (*input-wait-lock*)
(bt:condition-notify *input-wait-condition*))
(loop :while (listen *stream-input-string*))))
"Output from a thread 2"
"Output from a thread"
The following code illustrates the previous idea of mutating the original binding of *standard-output*. This has the downside of the mutation affecting all the threads.
(let ((original-stdout *standard-output*))
(with-output-to-string (stdout)
(unwind-protect
(progn
(setq *standard-output* stdout)
(bt:join-thread
(bt:make-thread
(lambda ()
(format *standard-output* "Hello World")))))
(setq *standard-output* original-stdout))))

This all seem a bit complex, and it looks like you are calling bt:join-thread to wait for the thread to finish. Unfortunately, this means that your main thread is blocked until the worker thread is finished, something that typically is a code smell in multi-threaded applications (if you block the main thread, you might as well call the function directly in the same thread).
In fact, when threads are involved, lexically scoped macros like with-X are usually either better done inside the thread, or not at all. I am going to use the lparallel library because it provides queues datastructures.
(defpackage :so (:use :cl))
(in-package :so)
(ql:quickload :lparallel)
Let's define a sample test function that uses standard input and output streams:
(defun test-function ()
"A test function that acts on standard input/output streams"
(format t "input is: ~s" (read-line)))
The following make-thread/redirect-io function takes a function to execute as well as its input as a string. It returns another function that will block until the thread terminates and return the accumulated output as a string. In practice you would also need to handle exceptions:
(defun make-thread/redirect-io (fn input-as-string)
(let ((queue (lparallel.queue:make-queue)))
(values (lambda () (lparallel.queue:pop-queue queue))
(bt:make-thread
(lambda ()
(lparallel.queue:push-queue
(with-output-to-string (*standard-output*)
(with-input-from-string (*standard-input* input-as-string)
(funcall fn)))
queue))))))
This allows you to really run things in parallel, for example you can spawn two threads with different inputs:
(let ((join-a (make-thread/redirect-io #'test-function "Hello"))
(join-b (make-thread/redirect-io #'test-function "World")))
;; do something else in parallel, do not join the thread otherwise
;; it would just be blocking as-if you called the function in the
;; same thread
;; then, get the results
(list (funcall join-a)
(funcall join-b)))
This returns the following list:
("input is: \"Hello\"" "input is: \"World\"")
In fact, I'd suggest using having a look at lparallel.org to see if you can use it directly, it can greatly simplify working with threads.

Related

Common lisp: calling a class method in a separate thread

I am trying to build a common lisp implementation of the channel construct of Golang for a personal project (also to learn lisp). So far I've implemented the channels as objects of a class, containing a queue, a lock and a condition variable to signal listening functions that a new message has been added to the queue. I'm using bordeaux threads to create threads, locks, condition variables and join the executions (from the lisp cookbook).
This is the channel class and the recive function:
(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
"Condtional variable to notify the channel of a new message")))
(defmethod recive-loop ((self channel))
(with-slots (lock cv messages) self
(let ((to-ret nil))
(loop
(bt:with-lock-held (lock)
(if (not (null messages))
(setf to-ret (car (pop messages)))
(bt:condition-wait cv lock))
(if to-ret (return to-ret)))))))
(defmethod recive ((self channel))
(with-slots (name thread) self
(let ((thread
(bt:make-thread #'(lambda() (recive-loop self))
:name name)))
(bt:join-thread thread))))
(defmacro gorun (f &rest args)
(flet ((fn () (apply f args)))
(bt:make-thread #'fn
:initial-bindings (list args)
:name "gorun worker")))
gorun should be the equivalent of go routine() for go (without the light threading). To test the setup I've built a printer function over a channel
(defvar printch (channel))
(defun printover (ch)
(let ((x (recive ch)))
(format t "Recived variable x: ~d~%" x)))
but when I run
(gorun printover printch)
The interpreter (using sbcl, but with clisp the same happens) gives back an error:
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::RECIVE (1)>
when called with arguments
(PRINTCH).
[Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]
See also:
Common Lisp Hyperspec, 7.6.6 [:section]
Restarts:
0: [RETRY] Retry calling the generic function.
1: [ABORT] abort thread (#<THREAD "gorun worker" RUNNING {100293E9F3}>)
Backtrace:
0: ((:METHOD NO-APPLICABLE-METHOD (T)) #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::RECIVE (1)> PRINTCH) [fast-method]
Locals:
SB-PCL::ARGS = (PRINTCH)
GENERIC-FUNCTION = #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::RECIVE (1)>
1: (SB-PCL::CALL-NO-APPLICABLE-METHOD #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::RECIVE (1)> (PRINTCH))
Locals:
ARGS = (PRINTCH)
GF = #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::RECIVE (1)>
2: (PRINTOVER PRINTCH)
Locals:
CH = PRINTCH
3: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
[No Locals]
I'm confused, since the method to run over the channel printch should be the one I've defined.
Trying to call a class method inside of a new thread, but got no applicable method
A macros is supposed to return code to run in place of the original call. Your macro is creating the thread at expansion time.
If you're not using backtick in a macro definition, there's usually something wrong with it. You should figure out what the code would look like without the macro, then define a macro that returns code with that same structure in a backticked list, replacing the places that need to vary with the parameters, using comma to expand them.
(defmacro gorun (f &rest args)
`(bt:make-thread (function ,f)
:initial-bindings (list ,#args)
:name "gorun worker"))
In the above, you need to substitute the function name into a (function ...) expression, and the args list as the :initial-bindings argument.
In multi-threaded environments it is often the case that special variables are thread-local. The global binding is visible from all threads, but if you bind one locally its value will not automatically be transferred to a thread created in that context. It has to be done explicitly, and I wrote a pair of macros recently just for that.
The first one captures bindings into lexically-scoped variables; the other bind the original variables back to the values captured in a different context.
I am using an intermediate data structure in the code to store bindings:
(defstruct bindings data)
The first macro is with-captured-bindings:
(defmacro with-captured-bindings ((&rest symbols) as name &body body)
(assert (eq as :as))
(loop for s in (alexandria:flatten
(sublis
'((:stdio *standard-output* *error-output* *standard-input*)
(:path *default-pathname-defaults*))
symbols))
for g = (gensym)
collect (list g s) into capture
collect (list s g) into rebind
finally
(return
`(let ,capture
,#(subst (make-bindings :data rebind)
name
body)))))
The capture variable holds a list of bindings to initialize the lexically-scoped variables. The rebind variables is a list of bindings to set back special variables to their values in another thread.
I inject with subst an instance of the bindings struct in the code. It helps to have a dedicated data structure, but the crude search-and-replace approach means the symbols name will not be usable as a function, local macro, etc. in body. I don't think it is too much of a problem.
Also, I define aliases like :stdio and :path for commonly used variables.
The second macro is with-bindings:
(defmacro with-bindings (bindings &body body)
(check-type bindings bindings)
`(let ,(bindings-data bindings)
,#body))
This replaces the intermediate struct with the proper code. The final code does not have this struct anymore and can be processed as usual.
For example:
(defvar *my-var* "hello")
(with-captured-bindings (:stdio :path *my-var*) :as <bindings>
(sb-thread:make-thread
(lambda ()
(with-bindings <bindings>
(print *var*)))))
A first application of macroexpand gives:
(LET ((#:G3882 *STANDARD-OUTPUT*)
(#:G3883 *ERROR-OUTPUT*)
(#:G3884 *STANDARD-INPUT*)
(#:G3885 *DEFAULT-PATHNAME-DEFAULTS*)
(#:G3886 *MY-VAR*))
(SB-THREAD:MAKE-THREAD
(LAMBDA ()
(WITH-BINDINGS #S(BINDINGS
:DATA ((*STANDARD-OUTPUT* #:G3882)
(*ERROR-OUTPUT* #:G3883)
(*STANDARD-INPUT* #:G3884)
(*DEFAULT-PATHNAME-DEFAULTS* #:G3885)
(*MY-VAR* #:G3886)))
(PRINT *MY-VAR*)))))
Notice that there is #S(BINDINGS ...) object in the tree.
The full expansion is:
(LET ((#:G3887 *STANDARD-OUTPUT*)
(#:G3888 *ERROR-OUTPUT*)
(#:G3889 *STANDARD-INPUT*)
(#:G3890 *DEFAULT-PATHNAME-DEFAULTS*)
(#:G3891 *MY-VAR*))
(SB-THREAD:MAKE-THREAD
(LAMBDA ()
(LET ((*STANDARD-OUTPUT* #:G3887)
(*ERROR-OUTPUT* #:G3888)
(*STANDARD-INPUT* #:G3889)
(*DEFAULT-PATHNAME-DEFAULTS* #:G3890)
(*MY-VAR* #:G3891))
(PRINT *MY-VAR*)))))

unread-char behaviour deviating from spec?

On the Common Lisp HyperSpec page for unread-char - see
here - it says both of the following things:
"unread-char is intended to be an efficient mechanism for allowing the Lisp reader and other
parsers to perform one-character lookahead in input-stream."
"It is an error to invoke unread-char twice consecutively on the same stream without an
intervening call to read-char (or some other input operation which implicitly reads characters)
on that stream."
I'm investigating how to add support for multiple-character lookahead for CL streams for a
parser I'm planning to write, and just to confirm the above, I ran the following code:
(defun unread-char-test (data)
(with-input-from-string (stream data)
(let ((stack nil))
(loop
for c = (read-char stream nil)
while c
do (push c stack))
(loop
for c = (pop stack)
while c
do (unread-char c stream)))
(coerce
(loop
for c = (read-char stream nil)
while c
collect c)
'string)))
(unread-char-test "hello")
==> "hello"
It doesn't throw an error (on SBCL or CCL, I haven't tested it on other implementations yet) but I don't see how there can possibly be any read
operations (implicit or explicit) taking place on the stream between the consecutive calls
to unread-char.
This behaviour is good news for multiple-character lookahead, as long as it is consistent, but why
isn't an error being thrown?
In response to user jkiiski's comment I did some more digging. I defined a function similar to the above but that takes the stream as an argument (for easier reuse):
(defun unread-char-test (stream)
(let ((stack nil))
(loop
for c = (read-char stream nil)
while c
do (push c stack))
(loop
for c = (pop stack)
while c
do (unread-char c stream)))
(coerce
(loop
for c = (read-char stream nil)
while c
collect c)
'string))
I then ran the following in a second REPL:
(defun create-server (port)
(usocket:with-socket-listener (listener "127.0.0.1" port)
(usocket:with-server-socket (connection (usocket:socket-accept listener))
(let ((stream (usocket:socket-stream connection)))
(print "hello" stream)))))
(create-server 4000)
And the following in the first REPL:
(defun create-client (port)
(usocket:with-client-socket (connection stream "127.0.0.1" port)
(unread-char-test stream)))
(create-client 4000)
And it did throw the error I expected:
Two UNREAD-CHARs without intervening READ-CHAR on #<BASIC-TCP-STREAM ISO-8859-1 (SOCKET/4) #x302001813E2D>
[Condition of type SIMPLE-ERROR]
This suggests that jkiiski's assumption is correct. The original behaviour was also observed when the input was read from a text file, like so:
(with-open-file (stream "test.txt" :direction :output)
(princ "hello" stream))
(with-open-file (stream "test.txt")
(unread-char-test stream)))
==> "hello"
I imagine that, when dealing with local file I/O, the implementation reads large chunks of a file into memory, and then read-char reads from the buffer. If correct, this also supports the assumption that the error described in the specification is not thrown by typical implementations when unreading from a stream whose contents are in-memory.

Dead lock in SBCL Thread

I was coding up a script for a research project using SBCL, and this is the first time I tried SB-TREAHD. Each thread will call external shell command several times, for which sb-ext:run-program is used.
The problem is that whenever ext:run-program is presented, the program can run into dead lock (where I did not use anything like mutex excplicitly). I experiment it for a while and couldn't find any solution. A simplified version of the code which can still make the dead lock happen is as follows:
(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)
where in (main) 4 threads are created, and each of them will run (first-iteration), and in (first-iteration) it calls (gen-conf) several times which involves both (sb-ext:run-program) and file I/O.
I thought maybe the dead lock is due to incorrectly using of sb-thread, but just by looking at the SBCL manual I cannot find out the correct way. Any suggestion will be helpful.
btw, to run the program, get http://pages.cs.wisc.edu/~breakds/thread.tar.gz which have all the required directories/files created.
Thank you!

Searching with intelligent bracket counting (Elisp)

I have the following function that deletes the LaTeX command surrounding the current cursor position:
(defun remove-tex-cmd ()
(interactive)
(save-excursion
(let (cur-point beg-point end-point)
(setq cur-point (point))
(catch 'notexcmd
(if (not (re-search-backward "\\.*?{" nil t)) ; now the point is at the {
(throw 'notexcmd nil))
(search-backward "\\" nil t)
(setq beg-point (point))
(re-search-forward "}")
(setq end-point (point))
(if (> end-point cur-point)
(kill-region beg-point end-point))
(throw 'notexcmd nil)))
(if 'notexcmd
(message "no tex command at point"))))
It works well except for the following situation, because it simply matches the next closing }:
\test{a<cursor here>sdf ${bla}+1$}
results in
+1$}
I could, of course, count the opening and closing brackets. However, as this problem should occur frequently, I wonder whether there exists some more intelligent search function, or am I missing a totally different point?
Use list- or sexp- based operations:
(defun remove-tex-cmd ()
(interactive)
(backward-up-list 1)
(backward-sexp 1)
(kill-sexp 2))
To handle scan error when outside parentheses:
(defun remove-tex-cmd ()
(interactive)
(condition-case nil
(progn
(backward-up-list 1)
(backward-sexp 1)
(kill-sexp 2))
(scan-error (message "Outside parentheses."))))

Simplest example of backwards continuations in Scheme without explicit mutation

I've written a small Scheme interpreter in C#, and realised that the way I had implemented it, it was very easy to add support for proper continuations.
So I added them... but want to "prove" that they way that I've added them is correct.
My Scheme interpreter however has no support for "mutating" state - everything is immutable.
So it was pretty easy to write a unit test to expose "upwards" continuations:
AssertEqual(Eval("(call/cc (lambda (k) (+ 56 (k 3))))"), 3);
However, I also want to write a unit test that demonstrates that if the continuation "escapes" then that still works too:
AssertEqual(Eval("(call/cc (lambda (k) k))", <some continuation>);
But of course, the above would just test that "I got a continuation"... not that it's actually a valid continuation.
All of the examples I can find, however, always end up using "set!" to demonstrate the escaped continuation.
What's the simplest Scheme example that demonstrates proper support for backwards continuations without relying on mutation?
Are backwards continuations any use without mutation? I am beginning to suspect that they are not, because you could only use it to execute the exact same calculation again... which is meaningless if there are no side-effects. Is this why Haskell does not have continuations?
I don't know if this is the simplest, but here's an example of using backwards continuations without any call to set! or similar:
(apply
(lambda (k i) (if (> i 5) i (k (list k (* 2 i)))))
(call/cc (lambda (k) (list k 1))))
This should evaluate to 8.
Slightly more interesting is:
(apply
(lambda (k i n) (if (= i 0) n (k (list k (- i 1) (* i n)))))
(call/cc (lambda (k) (list k 6 1))))
which computes 6! (that is, it should evaluate to 720).
You can even do the same thing with let*:
(let* ((ka (call/cc (lambda (k) `(,k 1)))) (k (car ka)) (a (cadr ka)))
(if (< a 5) (k `(,k ,(* 2 a))) a))
(Man, stackoverflow's syntax highlighting fails massively on scheme.)
I think you're right -- without mutation, backwards continuations do nothing that forward continuations can't.
Here's the best I've come up with:
AssertEqual(Eval("((call/cc (lambda (k) k)) (lambda (x) 5))", 5);
Not amazing, but it is a backwards continuation which I then "call" with the actual function I wish to invoke, a function that returns the number 5.
Ah and I've also come up with this as a good unit test case:
AssertEqual(Eval("((call/cc call/cc) (lambda (x) 5))", 5);
I agree with Jacob B - I don't think it's that useful without mutable state... but would be still be interested in a counter-example.
Functional Threads:
You can use a recursive loop to update state without mutation. including the state of the next continuation to be called. Now this is more complicated than the other examples given, but all you really need is the thread-1 and main loop. The other thread and "update" function are there to show that continuations can be used for more than a trivial example. Additionally, for this example to work you need an implementation with the named let. This can be translated into an equivalent form made with define statements.
Example:
(let* ((update (lambda (data) data)) ;is identity to keep simple for example
(thread-1
(lambda (cc) ;cc is the calling continuation
(let loop ((cc cc)(state 0))
(printf "--doing stuff state:~A~N" state)
(loop (call/cc cc)(+ state 1))))) ;this is where the exit hapens
(thread-2
(lambda (data) ;returns the procedure to be used as
(lambda (cc) ;thread with data bound
(let loop ((cc cc)(data data)(state 0))
(printf "--doing other stuff state:~A~N" state)
(loop (call/cc cc)(update data)(+ state 1)))))))
(let main ((cur thread-1)(idle (thread-2 '()))(state 0))
(printf "doing main stuff state:~A~N" state)
(if (< state 6)
(main (call/cc idle) cur (+ state 1)))))
Which outputs
doing main stuff state:0
--doing other stuff state:0
doing main stuff state:1
--doing stuff state:0
doing main stuff state:2
--doing other stuff state:1
doing main stuff state:3
--doing stuff state:1
doing main stuff state:4
--doing other stuff state:2
doing main stuff state:5
--doing stuff state:2
doing main stuff state:6

Resources