-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Make ElastixMain database creation + loading components thread safe #389
Conversation
07aea06
to
fcbd9e4
Compare
Removed the two `UnloadComponents()` member functions (from both `ElastixMain` and `ComponentLoader`), as they appear not useful anymore. Paves the way to making access to the ComponentDatabase thread-safe.
Ensures that only one thread may load the components into the ComponentDatabase, using using C++11 "magic statics". `ElastixMain::GetComponentDatabase()` now returns a "const reference" instead of a non-const pointer, to prevent one thread from modifying the database while another is reading from the database. Aims to fix issue #174 "elastix 4.9 static libary version not thread safe" reported by jiangliMED, August 16, 2019 With help from Konstantinos Ntatsis
fcbd9e4
to
5aa3c71
Compare
@ntatsisk Hi Konstantinos! Can you please review this pull request? And could you possibly also try it out, to see if it does indeed fix a multi-threading issue that you encountered? You may check out the (temporary) branch of this pull request: https://github.com/SuperElastix/elastix/tree/ElastixMain-LoadComponents-thread-safe |
Hello @N-Dekker, the solution looks great! I really liked the combination of magic statics together with a lambda function for the |
@ntatsisk Thank you for your approval and your enthusiastic reply! I certainly enjoyed combining magic statics together with a lambda 😃 May I ask what your use case looks like? So you call RegisterImages multiple times simultaneously within the same process? How do you do that? Something like |
@N-Dekker No, we are using OpenMP to parallelize the registrations. The idea is as follows:
As you see, we are trying to do many (simple) registrations but in a short amount of time (~<10sec) which is a requirement. So, it is better to split the registrations among the threads instead of using many threads for a single registration, as ITK threading does. The gain is some saved seconds eg. from 12sec (with the critical section) to 7sec (in the thread-safe version). In another part, it goes from 30sec to 10sec. Generally, these times might not seem like a big deal, but they are for our application ;) |
@mstaring @stefanklein Hope it's OK to you that I'll merge this pull request this afternoon! |
I do not get all the details of this PR, but i assume i) elastix still works (all tests pass for the command line version and ITKElastix also still works), and ii) it was verified that it actually fixes a problem (a new test first failed but now passes). |
@mstaring Thanks for your feedback
All elastix test are passed successfully, at the CI. However, I did not test ITKElastix with this pull request. We currently do not test ITKElastix on each elastix pull request. But I don't think ITKElastix would have any problem with this pull request. Unless it would try to call
It is verified by Konstantinos (@ntatsisk) that it actually fixes a problem. I can still see if an automatic test can be added, based on his use case. |
sounds good then! |
@ntatsisk Sorry I did not yet merge, because I'm still trying to write a unit test (GoogleTest) for this pull request. But if you need it now, I can just merge this and write the test later. What do you think? Anyway, I'm just trying (locally on my laptop):
But it says:
Do you have a suggestion? |
Hi @N-Dekker, I am not in a hurry at all with the merging so it can wait. Regarding the error, I assume you are compiling with "warnings as errors" because I have got the same message but as a warning instead. I used to get it while running in Debug mode but it has been a while since then. Maybe, it is coming from here: elastix/Components/Optimizers/StandardGradientDescent/itkGradientDescentOptimizer2.cxx Lines 212 to 224 in af382ee
Since this
Does this work? Btw, even if it does, I think your test will still crash due to the logger being thread-unsafe, right? |
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment) This unit test is expected to pass successfully only when the elastix component database is indeed thread-safe.
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment) This unit test is expected to pass successfully only when the elastix component database is indeed thread-safe.
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment) This unit test is expected to pass successfully only when the elastix component database is indeed thread-safe.
Thanks for the suggestion, Konstantinos, but as far as I can see, those lines of code are excluded from compilation, as they are part of the "else block" of an Anyway, I just submitted a new "ElastixFilter.UpdateInParallel" test: #393 My aim is to have a little test that just shows that this pull request (#389) really fixes a certain problem. But the test is still unstable! I see it crashing some times. Could you also please have a look? |
Ops, my bad! So, it is clearly not the point that is called (maybe this instead?). Anyway, I also noticed that, actually, all the Regarding the crashing, as I mentioned in my last comment, I think it is because of the logger ;) |
I believe so too. The logger is still troublesome. So then, is there still any possible test case for this specific pull request, which only improves the thread-safety of the component database? Update: I just added a little unit test that calls |
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment)
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment)
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment)
Originally based on a code snippet by Konstantinos Ntatsis at pull request SuperElastix#389 ("ENH: Make ElastixMain database creation + loading components thread safe"): SuperElastix#389 (comment)
Originally based on a code snippet by Konstantinos Ntatsis at pull request SuperElastix#389 ("ENH: Make ElastixMain database creation + loading components thread safe"): SuperElastix#389 (comment)
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"): #389 (comment)
Ensures that only one thread may load the components into the ComponentDatabase, using using C++11 "magic statics".
ElastixMain::GetComponentDatabase()
now returns a "const reference" instead of a non-const pointer, to prevent one thread from modifying the database while another is reading from the database.Removed the two
UnloadComponents()
member functions (from bothElastixMain
andComponentLoader
), as they appear not useful anymore.Aims to fix issue #174
"elastix 4.9 static libary version not thread safe"
reported by @jiangliMED, August 16, 2019
With help from Konstantinos Ntatsis (@ntatsisk)