I have a question regarding the thread safety of ACADOS. I see that the generated solvers are using mainly global variables, which are not thread-safe. I would like to run a bunch of solvers in parallel, so they can not share any memory. Intuitively, a solver should be able to run as a single instance and should not be dependent on external/global variables. Is there a way to compile a solver that will be thread-safe? Or what needs to be changed? Are the underlying solvers thread-safe?
I do not know much about thread safety, but let me try to answer:
I get that the template based interface is not thread safe as it is because of the global data.
I think it should be relatively easy to modify it, such that it works without global data.
The idea would be to make the create function return a pointer to a struct that contains the pointers to all the substructures (the ones that are currently global data).
This one would have to be passed to all the functions interacting with the solver later on.
Do you think there is an issue wrt thread safety besides global data?
If it is just about running multiple solvers in parallel, would it be enough to prevent name clashing in the global data?
This could be done even easier, by adding model_name prefix to all the global data of the solver.
Changing name of the variables would solve part of the issue, we could run different solvers in parallel but not the same one.
I think a good solution would be that acados_create will not create any variables, since creating variables in a function and returning pointer to them is not the safest thing. How about acados_create and any other function would accept a structure, containing all the global data needed. Then user can define how to construct the objects and they would be just filled in acados_create, so the signature of the function would change to int acados_create(all_global_data* data) . In this way, the user have the option to decide whether to use global data structure or local.
From bottom up, BLASFEO, HPIPM and acados core are 100% thread safe, as they use no global variables or static memory at all.
So using just these components, multiple solvers can co-exist.
Then yes it’s just a matter of what the interfaces on top are designed to do.
And there it is mainly a matter of tradeoffs with user friendliness.
The most common case by far is to use just a single solver, and priority goes into making the solver creation process “as automated as possible”.
On the other hand, leaving to the end user the complete responsibility of allocating all memory requires more work but gives the expert user complete control over such issues.
I made some changes in the C-templates to facilitate using multiple DIFFERENT template-solvers (single- or multi-threading) in one application. For this reason I changed the interface to contain the solver name and introduced a struct for encapsulating all global data as suggested in the posts above.
In order to support launching multiple threads of the SAME template-solver I would also suggest to provide an additional version of all template functions (create, free, solve, and update_params) with a pointer to the data structure being an argument. However, since I do not need this right now, I’ve not implemented it yet.