In this post I'll take a closer look at the ways in which Maple code can be thread unsafe. If you have not already seen my post on Thread Safety, consider reading that post first. As a brief review, a procedure is thread safe if it works correctly when run in parallel.
The most obvious way in which procedures can be thread unsafe is if they share data without synchronizing access (using a Mutex, for example). So how can two threads share data?
The most obvious way to share data is via global variables. Using global variables is generally considered bad programming anyway, so this is not really that serious a limitation. Unfortunately using global variables was a fairly common practice in the early days of Maple, so there are a few instances floating around in the library.
It may not be obvious at first, but module variable (both locals and exports) can allow threads to share data. If the module is accessible from multiple threads, then any variables within that module are shared variables. Often module variables are read only, which means they can be used without any problem, however if variables are assigned to, then they can cause problems.
M := module()
export setShared, getShared;
setShared := proc( s )
shared := s;
getShared := proc()
The module local shared is shared between threads. Thus calling getShared could return value that was set by another thread. Often module locals are used to maintain state that is related to the on going computation. This will not work properly if multiple threads are executing distinct computations.
There are a few Maple functions that accept a name as a parameter and assign a value to that name (for example gcd). If a shared variable is passed as one of these side effect variables, then that can be unsafe. Of course one could simply pass a procedure local variable (which is created on the stack, thus is thread local) to avoid this issue.
Maple allows users to define ?extension functions. There are two systems described, neither of which is really safe. The / mechanism is based around assigning to global names. The "Add" system uses a table stored as a module local. Thus two threads may attempt to create extension functions with the same name, but different behaviours. Clearly this would be unsafe.
Remember tables have the same scope as the function that has the remember table. Thus for a function assigned to a shared variable, that function's remember table is also shared. This may or may not be a problem. If the remember table is left to Maple to automatically manage, it will probably be safe. Given a specific set of inputs a specific output is returned. However some procedures use remember tables differently. Sometimes a procedure will explicitly modify its or another function's remember table, for example one functions may clear the remember table of another. If another threads is executing that function, clearing the remember table could seriously effect the correctness of that execution.