-
-
Notifications
You must be signed in to change notification settings - Fork 529
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
Improve locked queue deadlocks #601
Conversation
b93b5a6
to
5a3ee53
Compare
@hdiethelm: I would love to get your review on that, if you have time! :-) |
e9d02aa
to
31c2315
Compare
@julianoes Should this be a [WIP] PR? |
Oh, quite a lot of changes! I don't have the time to review all, sorry. I just looked a bit trough and so far it looks good! The only risk is that somewhere you do a borrow_front and forget the corresponding pop_front/return_front resulting also in a deadlock. I was thinking we could also drop locked_queue completely and instead use a normal queue as it is. Then add a mutex for each queue directly in MAVLinkParameters and MAVLinkCommands and lock it using lock_guard or unique_lock so unlocking is guaranteed. The disadvantage is if you forget to lock the mutex, you could mess up the queue. I have also an other idea, I'll just test if it works. |
Check this one: |
I added a test and it works: |
So, yes we can test for an assert using |
What do you think about my suggestion, passing a unique_lock with no associated mutex to borrow_front() to avoid an accidental lock without unlock? |
Thanks yes! I think that's definitely better because it can avoid mistakes. I was hoping that we can have the locked queue pass some kind of smart pointer thing that keeps the lock internal and returns if it goes out of scope. I didn't have time to try that though. |
unique_lock is one way of that kind of smart pointer.
My way is:
|
9f7b0a4
to
4d97764
Compare
I gave this a try to get to something close to the guard semantics:
See the last 3 commits. What do you think? |
Looks nice! I think that should do it! |
138bcd1
to
1748811
Compare
locked_queue: fix MSVC Debug unit test
is not so nice.
could be better. And then overwrite the copy constructor of QueueGuard = delete, so it can not be copied as it is done in unique_lock. Edit: added ``` around code. |
Ah, I didn't think of that, yes that would be nicer! |
Nice! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just reviewed this myself. I think it's all correct.
I would appreciate a review @JonasVautherin or @hdiethelm. @hdiethelm I made you a collaborator if you want to be involved 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spent some time reviewing that, and as far as I can tell, it looks good to me.
Awesome, thanks @JonasVautherin. I'll rebase and merge. |
In my opinion we dont really need the _state variable because we can derive what is going on from set timeouts and what is in the work queue. All that we actually need is to know if we already sent an item which has been added as a flag to each work item.
We can no longer do pops after the queue is empty and we always need to borrow before doing a pop.
This removes the state variable to prevent potential deadlocks. Instead a work item now contains a flag whether it has already been sent.
To make everything simpler it makes more sense to have one work queue instead of one for get and one for set. This way we just work through the items as they come in instead of an (unexpected) priorization of get over set. Also, this means that we can get rid of some code duplication, and other uglyness.
This is a try to use something like a lock guard instead of the borrow and return semantic.
This means all consumers need to switch to the new Guard semantics.
This fixes the unit test asserting for the MSVC debug build. The assert is prevented by using a workaround for this case where the return value optimization does not trigger and the move constructor is used.
This is closer to std::lock_guard and doesn't require a return copy/move of the Guard.
f095c8e
to
13955db
Compare
This is a further attempt following #590 to prevent potential deadlocks.