Title: queue.Queue() is not reentrant, so signals and GC can cause deadlocks
Type: crash Stage:
Components: Library (Lib) Versions: Python 3.6, Python 3.5, Python 3.3, Python 2.7
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: JohanAR, davin, itamarst, python-dev, rhettinger, sbt, tim.peters, zzzeek
Priority: normal Keywords:

Created on 2012-06-01 08:43 by JohanAR, last changed 2017-04-16 20:44 by itamarst. This issue is now closed.

File name Uploaded Description Edit JohanAR, 2012-06-01 09:39 signal hander reading/writing a queue
queue_sendint.c JohanAR, 2012-06-01 09:40 send 2 signals to specified process in rapid succession itamarst, 2017-04-16 20:44
Messages (11)
msg162062 - (view) Author: Johan Aires Rastén (JohanAR) Date: 2012-06-01 08:43
Python 2.7.3 (default, Apr 20 2012, 22:39:59) 
[GCC 4.6.3] on linux2

If a signal handler calls Queue.PriorityQueue.put and a second signal is received while one is already being processed, neither of the calls to put will terminate.

Highly dependent on timing so it might be difficult to reproduce.
msg162065 - (view) Author: Johan Aires Rastén (JohanAR) Date: 2012-06-01 09:44
Start in one terminal and note the PID it prints.

Compile queue_sendint.c in another terminal and execute it with previous PID as only argument.

If the bug is triggered, nothing will print in the python terminal window when you press Enter. To terminate the application you can press Ctrl-\
msg162069 - (view) Author: Richard Oudkerk (sbt) * (Python committer) Date: 2012-06-01 12:02
I don't think there is anything special about PriorityQueue.

There is a similar concerning the use of the Python implementation of RLock in signal handlers -- see

Maybe the signal handler should temporarily mask or ignore SIGINT while it runs.
msg162076 - (view) Author: Johan Aires Rastén (JohanAR) Date: 2012-06-01 14:43
I did read some more on the subject and it seems like using locks with interrupts is in general a very difficult problem and not limited to Python.

Don't know if this is considered common knowledge among programmers or if it would be useful with at least a warning on the signal manual page.
msg211436 - (view) Author: Itamar Turner-Trauring (itamarst) Date: 2014-02-17 18:50
This is not specifically a signal issue; it can happen with garbage collection as well if you have a Queue.put that runs in __del__ or a weakref callback function.

This can happen in real code. In my case, a thread that reads log messages from a Queue and writes them to disk. The thread putting log messages into the Queue can deadlock if GC happens to cause a log message to be written right after Queue.put() acquired the lock.
msg275181 - (view) Author: mike bayer (zzzeek) * Date: 2016-09-08 21:59
SQLAlchemy suffered from this issue long ago as we use a Queue for connections, which can be collected via weakref callback and sent back to put(), which we observed can occur via gc.    For many years (like since 2007 or so) we've packaged a complete copy of Queue.Queue with an RLock inside of it to work around it.

I'm just noticing this issue because I'm writing a new connection pool implementation that tries to deal with this issue a little differently (not using Queue.Queue though).
msg275377 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-09-09 18:38
Guido opposes having us going down the path of using an RLock and altering the queue module to cope with reentrancy. 

In the case of mixing signals with threads, we all agree with Johan Aires Rastén that "using locks with interrupts is in general a very difficult problem and not limited to Python", nor is it even limited to the queue module.  

I believe that the usual technique for mixing signals and threads is to have the signal handler do the minimal work necessary to record the event without interacting with the rest of the program.  Later, another thread can act on the recorded signal but can do so with normal use of locks so that code invariants are not violated.  This design makes reasoning about the program more tractable.
msg275404 - (view) Author: Roundup Robot (python-dev) Date: 2016-09-09 19:31
New changeset 137806ca59ce by Gregory P. Smith in branch '3.5':
Add a note about queue not being safe for use from signal handlers.

New changeset 4e15e7618715 by Gregory P. Smith in branch 'default':
Add a note about queue not being safe for use from signal handlers.
msg275421 - (view) Author: mike bayer (zzzeek) * Date: 2016-09-09 20:16
yep, that's what im doing in my approach.   though longer term thing, I noticed it's very hard to find documentation on exactly when gc might run.   E.g. would it ever run if I did something innocuous, like "self.thread_id = None" (probably not).   Just wasn't easy to get that answer.
msg275485 - (view) Author: Roundup Robot (python-dev) Date: 2016-09-09 22:59
New changeset 8c00cbbd3ff9 by Raymond Hettinger in branch '3.5':
Issue 14976:  Note that the queue module is not designed to protect against reentrancy
msg291764 - (view) Author: Itamar Turner-Trauring (itamarst) Date: 2017-04-16 20:44
This bug was closed on the basis that signals + threads don't interact well. Which is a good point.

Unfortunately this bug can happen in cases that have nothing to do with signals. If you look at the title and some of the comments it also happens as a result of garbage collection: in `__del__` methods and weakref callbacks.

Specifically, garbage collection can happen on any bytecode boundary and cause reentrancy problems with Queue.

The attached file is an attempt to demonstrate this: it runs and runs until GC happens and then deadlocks for me (on Python 3.6). I.e. it prints GC! and after that no further output is printed and no CPU usage reported.

Please re-open this bug: if you don't want to fix signal case that's fine, but the GC case is still an issue.
Date User Action Args
2017-04-16 20:44:34itamarstsetfiles: +

messages: + msg291764
versions: + Python 3.5, Python 3.6
2016-09-09 22:59:25python-devsetmessages: + msg275485
2016-09-09 20:16:38zzzeeksetmessages: + msg275421
2016-09-09 20:01:22davinlinkissue21009 superseder
2016-09-09 19:31:29python-devsetnosy: + python-dev
messages: + msg275404
2016-09-09 18:38:53rhettingersetstatus: open -> closed

nosy: + davin
messages: + msg275377

resolution: wont fix
2016-09-08 21:59:52zzzeeksetnosy: + zzzeek
messages: + msg275181
2014-02-24 14:55:10rhettingersetnosy: + tim.peters, rhettinger
2014-02-17 18:50:43itamarstsetversions: + Python 3.3
nosy: + itamarst
title: Queue.PriorityQueue() is not interrupt safe -> queue.Queue() is not reentrant, so signals and GC can cause deadlocks
messages: + msg211436

2012-06-01 14:43:01JohanARsetmessages: + msg162076
2012-06-01 12:02:09sbtsetnosy: + sbt
messages: + msg162069
2012-06-01 09:44:19JohanARsetmessages: + msg162065
2012-06-01 09:40:02JohanARsetfiles: + queue_sendint.c
2012-06-01 09:39:02JohanARsetfiles: +
2012-06-01 08:43:03JohanARcreate