Skip to content

Instantly share code, notes, and snippets.

@Goheeca
Last active November 17, 2019 18:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Goheeca/0a72da9703b8d2adf5d5d51caeeb4568 to your computer and use it in GitHub Desktop.
Save Goheeca/0a72da9703b8d2adf5d5d51caeeb4568 to your computer and use it in GitHub Desktop.
Multiprocess multithreaded computation with SBCL
#!/usr/bin/sbcl --script
(require :sb-posix)
(require :sb-bsd-sockets)
;;; Globals
;; IPC
(defvar *pid* nil)
(defvar *socket-path* "/tmp/socket")
(defvar *socket* nil)
;; MT
(defvar *running* nil)
(defvar *workers* nil)
(defvar *shared-resource* nil)
;;; Business check
(defun signal-finish ()
(sb-ext:atomic-update *running* #'1-))
(defun not-busy-p ()
(zerop *running*))
;;; Result collector
(defun status ()
(format t "Common(~a): ~{~a~^ ~}~%" *pid* *shared-resource*))
(defun add (elem)
(sb-ext:atomic-update *shared-resource* #'cons elem))
;;; Workers
(defun make-workers (count args)
(setf *running* count)
(setf *workers* (loop for i below count collect (apply #'make-worker (nth i args)))))
(defun join-workers (&optional (workers *workers*))
(mapc #'sb-thread:join-thread workers))
;;; Util
(defun color-formatter (color)
(format nil "~a[~am~~?~a[m" #\Esc color #\Esc))
(defun value (prefix inc)
(format nil "~?/~a/~a" (color-formatter (if (zerop *pid*) "1;31" "1;32")) `("~a" (,(if (zerop *pid*) "P" "C"))) prefix inc))
(defun make-worker (prefix count delay)
(sb-thread:make-thread
#'(lambda ()
(loop for i below count do
(add (value prefix i))
(sleep delay))
(signal-finish))))
;;; Fork
(defun mt-computation ()
(format t "The process ~a is starting.~%" *pid*)
(make-workers 2
`((,(format nil "~?" (color-formatter "1;33") '("~a" (a))) 100 0.0001)
(,(format nil "~?" (color-formatter "1;36") '("~a" (b))) 10 0.001)))
(loop named shower
do (status) (sleep 0.001)
when (not-busy-p) do (return-from shower))
(join-workers)
(format t "The process ~a is stopping.~%" *pid*))
(defun mp-computation ()
(when (probe-file *socket-path*) (delete-file *socket-path*))
(setf *pid* (sb-posix:fork))
(setf *socket* (make-instance 'sb-bsd-sockets:local-socket :type :stream))
(restart-case
(handler-bind ((sb-bsd-sockets:address-in-use-error #'(lambda (condition) (invoke-restart 'connect))))
(sb-bsd-sockets:socket-bind *socket* *socket-path*)
(sb-bsd-sockets:socket-listen *socket* 0)
(setf *socket* (sb-bsd-sockets:socket-accept *socket*)))
(connect () (sb-bsd-sockets:socket-connect *socket* *socket-path*)))
(if (zerop *pid*)
(format t "~a" (sb-bsd-sockets:socket-receive *socket* nil 100))
(sb-bsd-sockets:socket-send *socket* (format nil "The child ~a is starting.~%" *pid*) nil))
(mt-computation)
(if (zerop *pid*)
(format t "~a" (sb-bsd-sockets:socket-receive *socket* nil 100))
(sb-bsd-sockets:socket-send *socket* (format nil "The child ~a is stopping.~%" *pid*) nil))
(sb-bsd-sockets:socket-close *socket*))
;;; Main
(mp-computation)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment