modelica / fmi-standard

Specification of the Functional Mock-up Interface (FMI)
https://fmi-standard.org/
Other
271 stars 85 forks source link

Clarification of behavior regarding threads #517

Closed jnjaeschke closed 5 years ago

jnjaeschke commented 5 years ago

We encountered problems using FMUs from different threads. Depending on frameworks or libraries used (e.g. Qt, COM-Server) a FMU can crash when it is accessed from different threads (e.g. instantiated in thread A, used in thread B, free'd in thread C).

Quoting the FMI2 specification, sec. 2.1 "FMI Application Programming Interface":

FMI functions of one instance don't need to be thread safe. [For example, if the functions of one instance of an FMU are accessed from more than one thread, (...)]"

So, implicitly it is assumed that you may call FMUs from different threads. But it is not explicitly stated that the exporting tool has to ensure that the FMU works in a multi-threaded environment and can be instantiated, used and free'd from different threads.

Thinking of how much time it cost to figure out that this was a problem (and to find a solution for it) from both an importing and exporting tool vendor's view, I would propose to add a sentence to the specification stating

A FMU must by design be capable of being called from different threads. [It has to be expected that fmi functions are called from several threads. Any threading-sensitive portions of code have to be encapsulated in a fashion that they are not affected by being called from different threads.]

That way it is explicitly defined that a FMU must be robust enough to handle this and the exporting tool vendors are required to take care if they use thread-sensitive libraries.

pmai commented 5 years ago

Hmmm, how is this supposed to work? An FMU would have to be robust against all kinds of threading schemes, unknown to itself, since it does not know about the threading scheme used by the host (i.e. does the host use some form of green threads? Does it use OS-provided threads, does it roll its own? What are suitable locking schemes? What about necessary threading restrictions of the OS?).

While it would be nice to add informative (non-normative) text pointing out common problems, I don't think FMU authors can provide blanket guarantees that their code is going to work with any kind of threading system...

andreas-junghanns commented 5 years ago

I have to add to Pierre's scepticism: An FMU has a state and callers must know the state of the FMU. If multiple threads call into the FMU they all might change its state. They would have to share their understanding of which state the FMU is in in order to each comply with the standard's function call restrictions. If someone wants to go down this path, they can now do so. Why should every FMU add the overhead to be thread safe? If your environment requires this, you could add a thread-safety layer around the calls to the imported FMUs.

jnjaeschke commented 5 years ago

Fair enough...

Then how about going the other way and restrict the importing tools to only call the FMU from one thread? That would solve that problem as well. Calling a FMU multi-threaded is possibly not the best coding style anyways ...

andreas-junghanns commented 5 years ago

I don't understand: Why should we unnecessarily restrict the use of an FMU to a single thread? All we need to do is clarify that the FMU is not responsible for thread-safe usage and delegate this responsibility to the importer. What do we gain declaring one use case illegal?

jnjaeschke commented 5 years ago

Ah, how do I get out of this one? :)

Initially I wanted to propose "okay, let's state explicitly that it might be dangerous to (a) rely on threading-sensitive libraries on the exporter's side and (b) to use a FMU in a multi-threaded way". With that information given in the spec hopefully nobody tries to go that path(s) and one compatibility issue (and that is an acceptance issue for FMI!) is gone.

What I got out of your comments was "robustness can't be guaranteed (Pierre), using FMUs multi-threaded is dangerous (Andreas)". So I thought, okay what does one gain by allowing to use a FMU multi-threaded? I couldn't think of any points ... if you want to use a FMU multi-threaded, put it in a thread and communicate with it using that thread. Then you're safe.

That being said it was (my) logical conclusion. If we restrict this, the few people that would have implemented their FMU / importing tool in such a manner know that (and more important, they know why!) they have to change their code. And the other users that did not use such mean things in the first place won't care anyway.

Overall, this is a minor issue that 99% of users perhaps won't ever come across because presumably almost no FMUs rely on thread-sensitive libs and almost no importers use the FMUs multi-threaded. But for us, exactly that combination happened. Not just with our FMU and our tool but also with a FMU from a different vendor. And it cost some time to debug and find a solution for this (... which is "don't use FMUs multi-threaded. That only gets you into trouble.").

To conclude ... it would be okay for me to just put an informational message into the spec that says "when you use FMUs multi-threaded, we hope you know what you're doing. And if you export FMUs, have in mind that they might be used multi-threaded". But if we restrict it, we gain more safety as this problem can't occur anymore (at least not for valid FMUs and valid importing tools). And we lose... actually nothing (I guess). Even more, such a clear statement (especially if there also is a good motivation given for that decision) would lead to a clearer and better standard. Then there's no room for interpretation or devs thinking "ahh, nevermind, that might just work."

chrbertsch commented 5 years ago

This could be a clarificationin v2.0.1, right?

jnjaeschke commented 5 years ago

I think we still have not decided what to do about this. Talked to @pmai and @andreas-junghanns in Paderborn about this topic. What do we do about it? The more I think about it, a "clarifying" sentence in the specs should do. "Importers: Be aware that FMUs might have problems being called from different threads. Exporters: Be aware that importers might call FMU functions from different threads."

Restricting it would be way to much for a 2.0.1 release. And I'm not sure that I thought this through completely...

andreas-junghanns commented 5 years ago

Nothing in the standard says that FMU functions have to be made thread safe. This would effect state machines and a lot more. If you want thread safety, you have to handle this explicitly in the importer. I think this should be clear to anyone. Maybe it is not, so let's make sure in a sentence. Maybe in the description of canBeInstantiatedOnlyOncePerProcess?

APillekeit commented 5 years ago

As described above section 2.1 states:

FMI functions of one instance don't need to be thread safe.

Therefore if an additinal clarification is seen as required it should be added at this place in the documentation. In my view a clarification is not necessary.

chrbertsch commented 5 years ago

@jnjaeschke : Could you please propose a clarifying sentence in the specification? Or shall we close this?

chrbertsch commented 5 years ago

Decision in Webmeeting: close. If someone has concrete proposal, please open a PR