Встраивание Python с потоками, избегающими взаимоблокировок?

Есть ли способ внедрить python, разрешить обратные вызовы с python на C++, разрешить коду Python создавать потоки и избежать взаимоблокировок?

Проблема в следующем:

  • Чтобы вызвать Python, мне нужно удерживать GIL. Как правило, я делаю это, получая состояние основного потока при первом создании интерпретатора, а затем использую PyEval_RestoreThread() для получения GIL и замены состояния потока перед вызовом Python.

  • При вызове из Python мне может понадобиться доступ к некоторым защищенным ресурсам, которые защищены отдельным критическим разделом на моем хосте. Это означает, что Python будет удерживать GIL (возможно, из какого-то другого потока, а не того, который я изначально вызывал), а затем попытается получить мою защитную блокировку.

  • При вызове Python мне может потребоваться удерживать те же блокировки, потому что, например, я могу перебирать некоторую коллекцию объектов.

Проблема в том, что даже если я держу GIL при вызове Python, Python может отказаться от него, передать его другому потоку, а затем вызвать этот поток на мой хост, ожидая получить блокировки хоста. Тем временем хост может взять блокировки хоста и блокировку GIL и вызвать Python. Наступает тупик.

Проблема здесь в том, что Python передает GIL другому потоку, пока я вызываю его. Это то, что он должен делать, но делает невозможным блокировку последовательности - даже если я сначала возьму GIL, затем возьму свою собственную блокировку, а затем вызову Python, Python вызовет мою систему из другого потока, ожидая получить мою собственную блокировку (потому что он распаковал GIL, выпустив его).

Я не могу заставить остальную часть моей системы использовать GIL для всех возможных блокировок в системе — и это даже не сработает правильно, потому что Python все еще может освободить его для другого потока.

Я также не могу гарантировать, что мой хост не блокирует никаких блокировок при входе в Python, потому что я не контролирую весь код на хосте.

Так что, это просто случай, когда это невозможно сделать?


person Community    schedule 29.04.2009    source источник
comment
Не могли бы вы потребовать, чтобы ваш код C++ удерживал GIL до того, как он получит блокировки хоста?   -  person Dave    schedule 29.04.2009


Ответы (3)


«При вызове Python мне может потребоваться удерживать те же блокировки, потому что, например, я могу перебирать некоторую коллекцию объектов».

Это часто указывает на то, что один процесс с несколькими потоками не подходит. Возможно, это ситуация, когда несколько процессов — каждый с определенным объектом из коллекции — имеют больше смысла.

Независимый процесс — каждый со своим пулом потоков — может быть проще в управлении.

person S.Lott    schedule 29.04.2009
comment
Один процесс - это именно то, что мне нужно (данный процесс на самом деле является подключаемым модулем веб-браузера). Таким образом, к сожалению, ваше предложение не отвечает и не относится к моему вопросу. - person ; 29.04.2009
comment
Пожалуйста, дополните свой вопрос дополнительными фактами — не добавляйте информацию в комментарии. Плагин веб-браузера является новой информацией и относится к вопросу. - person S.Lott; 30.04.2009

Код, который вызывается python, должен освобождать GIL перед тем, как взять любую из ваших блокировок. Таким образом, я считаю, что он не может попасть в тупик.

person Douglas Leeder    schedule 29.04.2009
comment
Хороший ответ. Помните, что GIL существует только для защиты внутренних структур данных интерпретатора Python. Если поток вызывает какой-либо код, отличный от Python, он может безопасно освободить GIL во время выполнения этого кода. - person mhsmith; 19.07.2017

Недавно было обсуждение аналогичной проблемы в списке pyopenssl. Боюсь, если я попытаюсь объяснить это, то ошибусь, поэтому вместо этого я отошлю вас к проблема, о которой идет речь.

person Glyph    schedule 30.04.2009