My question: Do green threads naturally do atomic reads/writes to variables
such that mutexes are pragmatically not needed in most situations in
Chicken?

I have seen corrupted values which I assumed were due to reading/writing to
variables from multiple threads without mutex protection. However when I
tried to simulate this (code pasted below) I haven't been able to create
any collisions.

Note that where file handles and ports are being opened/closed with
subprocesses etc then mutexes are absolutely needed. I ran into this with
trying to use nanomsg in threads where subprocesses were being launched.
Without mutexes it crashed very quickly. It is possible that the corrupted
values I've seen in the past were actually due to open/closing of file
handles, ports and or processes along with cross threaded variable accesses.

But back to the question, are mutexes really needed when passing variables
back and forth between srfi-18 threads in Chicken? Perhaps my code below is
too simplistic to trigger a collision? Mutexes can have a pretty severe
impact on performance and it would be nice to know when they are really
needed. The srfi-18 documentation is crystal clear that they should be used
always but maybe in the case of chicken it is ok to bend the rules?

Thanks.
=====================
(use posix srfi-18 typed-records srfi-69)

(define-inline (with-mutex mtx accessor record . val)
  (mutex-lock! mtx)
  (let ((res (apply accessor record val)))
    (mutex-unlock! mtx)
    res))

(defstruct testit
  (x 0)
  (y 0))

(define *validvals* '(0 1 2 a b c d e f 3 4 5 6 7 8 9 "x" "y" "z" "*" "-"))
(define *numvals*   (length *validvals*))
(define *mtx* (make-mutex))

;; uncomment to try with a struct along with a mutex
(define *struct* (make-testit))
(define-inline (get-val)(with-mutex *mtx* testit-x *struct*))
(define-inline (set-val v)(with-mutex *mtx* testit-x-set! *struct* v))

;; uncomment to try with a struct, no mutex
;; (define *struct* (make-testit))
;; (define-inline (get-val)(testit-x *struct*))
;; (define-inline (set-val v)(testit-x-set! *struct* v))

;; uncomment to try with a global var, no mutex
;; (define *var* 0)
;; (define-inline (get-val) *var*)
;; (define-inline (set-val v) (set! *var* v))

;; uncomment to try with a hash table and no mutex
;; (define *var* (make-hash-table))(hash-table-set! *var* "value" 0)
;; (define-inline (get-val)(hash-table-ref *var* "value"))
;; (define-inline (set-val v)(hash-table-set! *var* "value" v))

(define (mod-struct)
  (let loop ((c 10000)
             (last-val #t)
             (same-count 0))
     (if (> c 0)
         (begin
            (if (not (member (get-val) *validvals*))
                (print "BAD VALUE: " (get-val)))
            (set-val (list-ref *validvals* (random *numvals*)))
            ;; (display (with-mutex *mtx* testit-x *struct*))
            (loop (- c 1) (get-val) (+ same-count (if (eq? (get-val)
last-val) 1 0))))
         (print "All done, same-count=" same-count " c=" c))))

(let ((threads (let loop ((c 100)
                          (r '()))
                  (if (> c 0)
                      (loop (- c 1)
                            (cons (make-thread mod-struct (conc
"mod-struct-" c)) r))
                      r))))
   (map thread-start! threads)
   (map thread-join!  threads))
_______________________________________________
Chicken-users mailing list
Chicken-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-users

Reply via email to