Ответ 1
Ошибка возникает из-за плохого взаимодействия между фиктивными объектами потока, созданными API threading
при вызове threading.currentThread()
на внешний поток и функция threading._after_fork
, вызываемая для очистки ресурсов после вызова os.fork()
.
Чтобы обойти ошибку без изменения источника Python, monkey-patch threading._DummyThread
с реализацией __stop
import threading
threading._DummyThread._Thread__stop = lambda x: 42
Причину ошибки лучше всего сузить в комментариях Richard Oudkerk и cooyeah. Случается следующее:
-
Модуль
threading
позволяет вызыватьthreading.currentThread()
из потока, не созданного вызовамиthreading
API. Затем он возвращает экземпляр "фиктивный поток", который поддерживает очень ограниченное подмножество APIThread
, но по-прежнему полезен для идентификации текущего потока. -
threading._DummyThread
реализуется как подклассThread
.Thread
экземпляры обычно содержат внутренний вызываемый (self.__block
), который ссылается на блокировку уровня ОС, выделенную для экземпляра. Поскольку общедоступные методыThread
, которые могут закончиться использованиемself.__block
, переопределяются конструктором_DummyThread
,_DummyThread
, преднамеренно освобождают блокировку уровня ОС, удаляяself.__block
. -
threading._after_fork
прерывает инкапсуляцию и вызывает частныйThread.__stop
метод для всех зарегистрированных потоков, включая фиктивные, где__stop
никогда не предназначалось для вызова. (Они не были запущены Python, поэтому их остановка также не управляется Python.) Поскольку фиктивные потоки не знают о__stop
, они наследуют его отThread
, и эта реализация с удовольствием обращается к закрытому__block
, который не существует в экземплярах_DummyThread
. Этот доступ, наконец, вызывает ошибку.
Исправлена ошибка в ветки 2.7 с помощью изменение Thread.__stop
не прерывать, когда __block
удаляется. Разница 3.x, где __stop
записана как _stop
и поэтому защищена, исправляет ее переопределяет _DummyThread
_stop
, чтобы ничего не делать.