Re: Maxima and thread safety

David Scherfgen via Maxima-discuss <[email protected]> Tue, 9 Jun 2026 17:15:15 +0200
Newsgroups gmane.comp.mathematics.maxima.general
Message-ID <CAMTHLKgHNxUjTSTQp784_SHgpCZKsMyXpD++GEN9GESy+fgzRg@mail.gmail.com>
Hi Michel,

You might add this to your examples:

distribute_over_tranches(
  '(block(
      [x_n: float(N), x_next, i],
      for i : 1 thru 1000 do (
          x_next: 0.5 * (x_n + N / x_n),
          x_n: x_next
      ),
      x_n)),
  N, 1000, 16);

Nothing fancy, it's Newton's algorithm to compute the square root, with a
fixed number of iterations, just for demonstration purposes.
Note that I have done everything possible to make sure that the variables
x_n, x_next, i are local, by using a block.
But yet, the calculation crashes as soon as one uses more than 1 thread.
So, the situation is even more delicate than I thought.

Best regards
David

Am Di., 9. Juni 2026 um 16:45 Uhr schrieb Michel Talon <
[email protected]>:

> I have updated the README in
>
> https://github.com/mtalon/mtalon/tree/master/mtalon/maxima-parallel
>
> to reflect David insightful examples.
>
> Finally "distribute_over_tranches_thread.lisp" is another way to
> achieve the same parallelism, using threads in just one Unix
> process. Here we use the sbcl threading support. For sufficiently
> independent computations one may expect to get correct behaviour.
> However if threads modify the internal state of maxima chaos can
> occur. Examples have been provided by David Scherfgen, notably:
> distribute_over_tranches('(concat('v, i) :: i), i, 10000, 16)$
> which under the hood affect the global variable $values, so at the end
> one gets length($values) different from 10000. The problem is that special
> variables with global extent are not bound in thread local storage, but
> can be read and modified independently by all threads. But they are not
> protected by a mutex.
> A small lisp program which  shows the behavior of such special global variables is:
>
> ;;; We are in main thread
> (defparameter *x* 0)
> (format nil "~a" *x*)    ;;; value of global *x* in main thread
> (let ((*x* 1))
> a  (format t "~a ~%" *x*)  ;;; value of *x* in main thread TLS
>   (sb-thread:make-thread (lambda ()   ;;; spawning new thread
> 			   (format t "~a ~%" *x*) ;;; value of *x* in new thread, the global one.
> 			   (setq *x* 3)
> 			   (format t "~a ~%" *x*) ;;; altered value of *x* in new thread
> 			   "Sorry! *x* in main thread is not isolated.")))
> (format nil "~a" *x*)     ;;; The global value of *x* has been altered in main thread
>
> However i still believe that the threading program may be very useful to distribute a bunch of "ordinary standard"
> computations over the many cores of modern processors.  For example running the same computation a hundred of times for
> different values of parameters which may take hours of compute time, will be scaled down basically by the number of cores.
> Fortunately special variables bound locally in a let form or similar  (this being called dynamically bound) get bound in TLS
> (thread local storage) which isolates them from thread to thread, so that most parts of maxima can still work OK.
>
>
> Le 07/06/2026 à 16:55, David Scherfgen a écrit :
>
>
> Unfortunately, Maxima has many hidden side effects that are surprising to
> the average user. The following innocent looking example simply creates
> Maxima variables v1, v2, v3, ..., v10000 in 16 parallel threads:
>
> --
> Michel Talon
>
> _______________________________________________
> Maxima-discuss mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/maxima-discuss
>

_______________________________________________
Maxima-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/maxima-discuss