ModelicaSpecification
ModelicaSpecification copied to clipboard
Ensure that pure functions are thread-safe
Reported by hansolsson on 17 Feb 2015 10:30 UTC I believe we should make it clearer that pure Modelica functions are also thread-safe.
The definition of pure Modelica function in section 12.3 of the 3.3r1 specification could already be interpreted as stating that pure functions are thread-safe, since there is no requirement that one call must be completed before the next one starts.
However, it should be made 100% clear to avoid any ambiguity. The non-normative text about caching should also mention that maintaining a cache will be more complicated due simultaneous calls.
An alternative would be to have a set of concurrency annotations and state that pure does not guarantee thread-safety; I believe that will be more complicated and of limited use for pure functions. For functions using external objects we might need an indication that they are conditionally thread-safe as long as they "write" to different external objects.
The reason this is becoming important is that we would like to run models in parallel, which means we need to know that functions are fully pure - including thread-safety.
Migrated-From: https://trac.modelica.org/Modelica/ticket/1660
Comment by beutlich on 17 Feb 2015 12:51 UTC Arent't you also interested in impure Modelica functions that are thread-safe? If yes, a different annotation would be needed instead of reusing the Impure annotation.
Comment by hansolsson on 17 Feb 2015 14:19 UTC Replying to [comment:1 beutlich]:
Arent't you also interested in impure Modelica functions that are thread-safe? If yes, a different annotation would be needed instead of reusing the Impure annotation.
Short answer: Not really.
Long answer:, with the several parts to this:
-
'pure' implies thread-safe (at least to me) and we should just clarify that. As I understand it pure in Fortran 95 also implies thread-safety, and it would be odd if we used something else.
-
impure functions can only be used in when-clauses and a few other places; i.e. there is less need to optimize that by running it in multiple threads.
-
Using impure functions will require more - not only marking them as 'thread-safe' - since we may have an algorithm with more than one call of an impure function. Mixing such an algorithm with another algorithm may produce odd results:
model M
Real x;
algorithm
when sample(1,1) then
Modelica.Utilities.Streams.print("The value of ");
Modelica.Utilities.Streams.print(getInstanceName());
Modelica.Utilities.Streams.print(" is ");
Modelica.Utilities.Streams.print(String(x));
end when;
end M;
Using multiple instances of this model in multiple threads will lead to the log being messed up - even if print is marked as thread-safe but impure (I understand there can be similar problems with writing data to some external devices). Getting a correct design for that will take more effort (concatenating the strings before calling print is the obvious solution here).
- One would expect that a function modifying the external world uses external objects (which print doesn't), and they would thus be conditionally safe if each external object (one of the inputs) is only used by one thread at a time. This seems to indicate that the annotation for an impure "reasonably thread-safe" function uses something (=external object input) that does not exist for pure functions.
Modified by beutlich on 24 Apr 2015 12:07 UTC
Comment by hansolsson on 5 Jan 2016 13:56 UTC Proposed wording (between 2nd and 3rd bullet in 12.3):
A pure Modelica function is thread-safe, i.e. multiple threads can call this function (and other pure Modelica functions) simultaneously while getting the same results as if they were called sequentially.
-- To me this is (as previously indicated) a clarification. Note that if the pure function internally uses caching ensuring thread-safety adds to the implementation cost, but I don't think we can treat multiply threads as an exceptional case anymore. -- Having some way of specifying conditionally safe (normally impure) functions using external objects would be interesting (conditionally safe=thread-safe as long as they are the only users of the specific external object), but seems like a large change that would deserve an MCP - probably in combination with other thread-safety aspects.
The "conditional safe" idea above is just one possibility, and there are also other ways of handling thread-safety - I could provide input about the Dymola 2016 annotations (ThreadSafe and CriticalRegion="...") for that MCP.