Подтвердить что ты не робот

Понять pingon threading bug

Чтение http://bugs.python.org/msg160297, я вижу простой script, написанный Стивеном Уайтом, который демонстрирует, как ошибки python с этим исключением

Exception AttributeError: AttributeError("'_DummyThread' object has no attribute '_Thread__block'",) in <module 'threading' 

Учитывая исходный код Стивена Уайта (http://bugs.python.org/file25511/bad-thread.py),

import os
import thread
import threading
import time

def t():
    threading.currentThread() # Populate threading._active with a DummyThread
    time.sleep(3)

thread.start_new_thread(t, ())

time.sleep(1)

pid = os.fork()
if pid == 0:
    os._exit(0)

os.waitpid(pid, 0)

как мы могли бы перезаписать его так, чтобы эта ошибка была решена?

4b9b3361

Ответ 1

Ошибка возникает из-за плохого взаимодействия между фиктивными объектами потока, созданными API threading при вызове threading.currentThread() на внешний поток и функция threading._after_fork, вызываемая для очистки ресурсов после вызова os.fork().

Чтобы обойти ошибку без изменения источника Python, monkey-patch threading._DummyThread с реализацией __stop

: no-op >
import threading
threading._DummyThread._Thread__stop = lambda x: 42

Причину ошибки лучше всего сузить в комментариях Richard Oudkerk и cooyeah. Случается следующее:

  • Модуль threading позволяет вызывать threading.currentThread() из потока, не созданного вызовами threading API. Затем он возвращает экземпляр "фиктивный поток", который поддерживает очень ограниченное подмножество API Thread, но по-прежнему полезен для идентификации текущего потока.

  • 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, чтобы ничего не делать.