-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Deadlock when exiting Progress context #90
Comments
Thanks for the analysis! Saved a lot of legwork. You're exactly right about the problem, but I think the solution may be to ensure that the refresh thread join is never done inside the progress._lock. Also the code I had to make the context manager re-entrant just complicated things. I've made the enter and exit simply call start and stop. If you wouldn't mind, have a look at #92 It seems to fix the deadlock. |
That's in master now. Thanks for the help! |
Do you have any estimate as to when the next pypi release will be? |
Released v1.2.3 just recently |
I can consistently reproduce this by letting the following script run. Eventually the progress bars will hang when they're nearly full, like so:
I believe the problematic sequence of events is as follows:
The main thread exits from a
Progress
context and acquiresProgress._lock
inProgress.__exit__()
https://github.com/willmcgugan/rich/blob/55988c6e721cc03ab4f6dc6aeca3089e7c5c13ae/rich/progress.py#L447-L451
The refresh thread finishes waiting on
_RefreshThread.done
and callsProgress.refresh()
, at which point it starts waiting forProgress._lock
https://github.com/willmcgugan/rich/blob/55988c6e721cc03ab4f6dc6aeca3089e7c5c13ae/rich/progress.py#L346-L348
https://github.com/willmcgugan/rich/blob/55988c6e721cc03ab4f6dc6aeca3089e7c5c13ae/rich/progress.py#L574-L582
The main thread calls
Progress._refresh_thread.stop()
inProgress.stop()
, at which point it waits for the refresh thread to finish with_RefreshThread.join()
https://github.com/willmcgugan/rich/blob/55988c6e721cc03ab4f6dc6aeca3089e7c5c13ae/rich/progress.py#L422-L436
https://github.com/willmcgugan/rich/blob/55988c6e721cc03ab4f6dc6aeca3089e7c5c13ae/rich/progress.py#L342-L344
At this point the main thread is holding
Progress._lock
and waiting on the refresh thread to finish while the refresh thread is waiting to acquireProgress._lock
so it can finish.I don't think it's safe to call
_RefreshThread.join()
while holdingProgress._lock
, because there's always a chance that the refresh thread started waiting onProgress._lock
the nanosecond after it was acquired.The text was updated successfully, but these errors were encountered: