common lisp - How to utilize the SBCL provided semaphore against race conditions -


as far knowledge semaphores goes, semaphore used protect resources can counted , vulnerable race conditions. while reading sbcl documentation of semaphores not figure out, how use provided semaphore implementation protect resource.

a usual work flow, recall be:

  1. a process wants retrieve of semaphore protected data (which sake of example trivial queue). semaphore counter 0, process waits

  2. another process puts in queue , semaphore incremented, signal sent waiting processes

given possibility of interleaving, 1 has protect of resource accesses might not in order, or linear order @ all. therefore e.g. java interprets each class implicit monitor , provides syncronized keyword programmer can define protected area can accessed 1 process @ time.

how emulate functionality in common-lisp, pretty sure current code thread safe without semaphore, semaphore has no clue code protect.

;;the package  (defpackage :tests (:use :cl :sb-thread))  (in-package :tests)  (defclass thread-queue ()   ((semaphore     :initform (make-semaphore :name "thread-queue-semaphore"))    (in-stack     :initform nil)    (out-stack     :initform nil)))   (defgeneric enqueue-* (queue element)   (:documentation "adds element queue"))  (defgeneric dequeue-* (queue &key timeout)   (:documentation "removes , returns first element out"))  (defmethod enqueue-* ((queue thread-queue) element)   (signal-semaphore (slot-value queue 'semaphore))   (setf (slot-value queue 'in-stack) (push element (slot-value queue 'in-stack))))   (defmethod dequeue-* ((queue thread-queue) &key timeout)   (wait-on-semaphore (slot-value queue 'semaphore) :timeout timeout)   (when (= (length (slot-value queue 'out-stack)) 0)     (setf (slot-value queue 'out-stack) (reverse (slot-value queue 'in-stack)))     (setf (slot-value queue 'in-stack) nil))   (let ((first (car (slot-value queue 'out-stack))))     (setf (slot-value queue 'out-stack) (cdr (slot-value queue 'out-stack)))     first))   (defparameter *test* (make-instance 'thread-queue))  (dequeue-* *test* :timeout 5)  (enqueue-* *test* 42)  (enqueue-* *test* 41)  (enqueue-* *test* 40)  (dequeue-* *test* :timeout 5)  (dequeue-* *test* :timeout 5)  (dequeue-* *test* :timeout 5)  (dequeue-* *test* :timeout 5) 

what have semaphore of count = 0, on consumers wait.

what need exclusive lock around access stacks (perhaps 1 each), or alternatively lock-free queue. if want/must use semaphores, binary semaphore can serve exclusive lock.


edit: in sbcl, have lock-free queues, might want use 1 of these instead of 2 stacks. possibility use atomic operations.

finally, if still doesn't suit you, use mutex, wrapping code acesses , updates stacks inside with-mutex or with-recursive-lock.

be sure use lock/mutex after waking semaphore, not around waiting semaphore, otherwise lose advantage semaphores give you, possibility of waking multiple waiters in row, instead of 1 @ time.

you can read these things in sbcl manual.

also, think work has been done rename every lock-like thing in sbcl lock, according this blog post, don't know status of , states old names supported while.


you'll surely need semaphore of count = limit producers, not exceed queue limit.

in enqueue-*, should signal semaphore after updating queue. setf not needed, push stores new head of list in place.

in dequeue-*, length lengthy function when applied lists, checking if list empty cheap null or endp. instead of taking car , store cdr, can use pop, that.


Comments

Popular posts from this blog

basic authentication with http post params android -

vb.net - Virtual Keyboard commands -

css - Firefox for ubuntu renders wrong colors -