Two-Phase Termination
さてTwo-Phase Termination - qnzm.log(クニジマログ)。
javaのinterruptを再現したかったけど、諦めた。
sb-thread:interrupt-threadで割り込みはかけられるんだけど、スレッドのステータスをとる方法が分からない。
ffiを使って取得してみようか、と一瞬考えたけど、linuxのpthreadでのスレッドの状態をとる方法も分からない。
で、素直に写経することにした。最近いまいちだな。
日付関数を使うのが始めて。そういえばつかったことなかったな。
get-decoded-timeで多値がかえる。でも多値ってなんか使いづらいな。。。
return、return-from、with-slotsを使ったのも始めてか。with-slotsは便利。
気がついたことは、or、andがさらっとかけない。ifを使わずに書きたい年頃なんだけど、ぱっと書けなくてなさけない。
それから、wait-lockを細かく使うとなにか気持ちがいい。
(defmacro with-lock(sem &body body) (let ((gsem (gensym))) `(let ((,gsem ,sem)) (unwind-protect (progn (sb-thread::wait-on-semaphore ,gsem) ,@body) (sb-thread::signal-semaphore ,gsem))))) (defmacro waitfor(sem test &body body) (let ((gsem (gensym))) `(let ((,gsem ,sem)) (unwind-protect (progn (sb-thread::wait-on-semaphore ,gsem) (do () (,test) (sb-thread::signal-semaphore ,gsem)) (progn ,@body)) (sb-thread::signal-semaphore ,gsem))))) (defun strcon(&rest items) (apply #'concatenate 'string (mapcar #'write-to-string items))) (defun get-datetime-string() (multiple-value-bind (sec min hour date mon y day p zone) (get-decoded-time) (strcon hour min sec))) (defclass logger () ((th :accessor logger-thread :initform nil) (sm :accessor logger-semaphore :initform nil) (started :accessor logger-started :initform nil) (finished :accessor logger-finished :initform nil))) (defmethod initialize-instance :after ((l logger) &rest intargs) (setf (logger-semaphore l) (sb-thread::make-semaphore :name (symbol-name (gensym)))) (sb-thread::signal-semaphore (logger-semaphore l))) (defmethod logger-start((l logger)) (with-slots (th sm started finished) l (with-lock sm (or (not started) finished (return-from logger-start nil))) (setf th (sb-thread:make-thread #'(lambda () (do () ((with-lock sm finished) (return nil)) (with-lock sm (setf started t)) (format t "start ~A ~%" (get-datetime-string)) (sleep 2) (format t "end ~A ~%" (get-datetime-string)))) :name (symbol-name (gensym)))) th)) (defmethod logger-stop ((l logger)) (with-slots (sm started finished) l (with-lock sm (or started (return-from logger-stop)) (and finished (return-from logger-stop)) (setf finished t)))) (sb-thread:make-thread #'(lambda () (setf log (make-instance 'logger)) (format t "log start~%") (logger-start log) (sleep 5) (format t "log end~%") (logger-stop log))) (do ((cmd (read-line) (read-line))) ((string= cmd "exit") 'DONE))