From: Bing on
I tinkered with SBCL threads:

(defun demo-threads (n &key (nthreads 4))
"Every thread fill its part of an array with its index number."
(let ((result (make-array n :initial-element nil)))
(flet ((thread-fn (idx start end)
(loop for i from start below end
do (setf (aref result i) idx))))
(let ((threads (loop with d = (ceiling n nthreads)
for i below nthreads
for start = (* i d)
for end = (min n (+ start d))
when (< start n)
collect (sb-thread:make-thread
(lambda () (thread-fn i start end))
:name (format nil "(thread-fn ~D ~D
~D)" i start end)))))
;; wait until all threads are
finished
(loop for thread in threads do (sb-thread:join-thread
thread)))
result)))

;; this is OK
CL-USER> (demo-threads 16)
#(0 0 0 0 1 1 1 1 2 2 2 2 3 3 3
3)

;; not OK
CL-USER> (demo-threads 16)
#(0 0 0 0 1 1 1 1 NIL NIL NIL NIL 4 4 4
4)

Is it correct to write to an array without mutex?
Software is sbcl-1.0.33-darwin-x86-64 on MacOSX 10.6.2.
From: D Herring on
Bing wrote:

> Is it correct to write to an array without mutex?

A mutex should only be necessary if multiple threads may access (with
at least one writing to) the same array index. I'd also guess fill
pointers are a bad idea.

Non-overlapping accesses into preallocated arrays should be fine.

- Daniel
From: Bing on
What I not understand is what happens the second example. The third
thread seems not to be initialized but the fourth thread stores 4 into
the array.

This number is given as IDX to the local function THREAD-FN and is
derived from the FOR loop. But the loop index runs only from 0 to
NTHREADS-1 (in this case 3) so were does the 4 came from? And why is
thread #3 not started?
From: Alan Bawden on
Bing <bernd.beuster(a)googlemail.com> writes:

> I tinkered with SBCL threads:
>
> (defun demo-threads (n &key (nthreads 4))
> "Every thread fill its part of an array with its index number."
> (let ((result (make-array n :initial-element nil)))
> (flet ((thread-fn (idx start end)
> (loop for i from start below end
> do (setf (aref result i) idx))))
> (let ((threads (loop with d = (ceiling n nthreads)
> for i below nthreads
> for start = (* i d)
> for end = (min n (+ start d))
> when (< start n)
> collect (sb-thread:make-thread
> (lambda () (thread-fn i start end))
> :name ...

I suspect your problem is caused by the fact that I, START and END are all
-assigned- to new values each time around the LOOP. Think about it...
From: Tobias C. Rittweiler on
Bing <bernd.beuster(a)googlemail.com> writes:

> I tinkered with SBCL threads:
>
> (defun demo-threads (n &key (nthreads 4))
> "Every thread fill its part of an array with its index number."
> (let ((result (make-array n :initial-element nil)))
> (flet ((thread-fn (idx start end)
> (loop for i from start below end
> do (setf (aref result i) idx))))
> (let ((threads (loop with d = (ceiling n nthreads)
> for i below nthreads
> for start = (* i d)
> for end = (min n (+ start d))
> when (< start n)
> collect (sb-thread:make-thread
> (lambda () (thread-fn i start end))
> :name (format nil "(thread-fn ~D ~D
> ~D)" i start end)))))
> ;; wait until all threads are
> finished
> (loop for thread in threads do (sb-thread:join-thread
> thread)))
> result)))
>
> ;; this is OK
> CL-USER> (demo-threads 16)
> #(0 0 0 0 1 1 1 1 2 2 2 2 3 3 3
> 3)
>
> ;; not OK
> CL-USER> (demo-threads 16)
> #(0 0 0 0 1 1 1 1 NIL NIL NIL NIL 4 4 4
> 4)
>
> Is it correct to write to an array without mutex?
> Software is sbcl-1.0.33-darwin-x86-64 on MacOSX 10.6.2.

Your example works fine for me on Linux; threads are known to be a bit
flaky on Darwin. As your example makes a nice small and self-contained
test case, I think it's appropriate to submit it to

https://bugs.launchpad.net/sbcl

-T.