2010-06-07 1 views
2

Я пытаюсь написать класс C++, который вызывает методы Python класса, который выполняет некоторые операции ввода-вывода (файл, stdout) сразу. Проблема, с которой я столкнулся, заключается в том, что мой класс вызывается из разных потоков: иногда основной поток, а иногда и другие. Очевидно, я попытался применить подход для вызовов Python в многопоточных приложениях. В основном все начинается с PyEval_AcquireLock и PyEval_ReleaseLock или только с глобальными замками. Согласно документации here, когда нить уже заблокирована, наступает тупик. Когда мой класс вызывается из основного потока или другого, который блокирует выполнение Python, у меня есть тупик.Python C API из приложения C++ - знать, когда блокировать

Python> Cfunc1() - C++ FUNC, что создает потоки внутренне, которые приводят к призывам в «мой класс», Он застрял на PyEval_AcquireLock, очевидно, Python уже заблокирован, т.е. ожидание C++ Cfunc1 вызов завершить ... Это отлично, если я опускаю эти блокировки. Также он отлично подходит, когда интерпретатор Python готов для следующей пользовательской команды, то есть когда поток вызывает funcs в фоновом режиме, а не внутри собственного вызова

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

Любой известный API или решение для этого?

(Python 2.4)

+0

У вас есть какой-то насос сообщений, куда вы отправляете сообщения, которые обрабатываются в основном потоке? – kibibu

+0

Можете ли вы объяснить, как возникают нитки? Являются ли они порождены через API Python? –

ответ

2

Если вы не обернули свой C++ код довольно странно, когда любой Python поток вызывает в вашем C++ код, то GIL является провел. Вы можете освободить в своем коде на C++ (если вы хотите выполнить некоторую потребительскую задачу, которая не требует взаимодействия с Python), а затем придется снова ее приобретать, когда вы хотите выполнить какое-либо взаимодействие с Python - см. the docs: если вы используете только старый добрый C API, есть макросы для этого, и рекомендуются идиом

Py_BEGIN_ALLOW_THREADS 
...Do some blocking I/O operation... 
Py_END_ALLOW_THREADS 

Документы объяснить:

Py_BEGIN_ALLOW_THREADS макрос открывает новый блок и объявляет скрытая локальная переменная ; макрос Py_END_ALLOW_THREADS закрывает блок . Другим преимуществом использования этих двух макросов является то, что когда Python скомпилирован без поддержки нитей, они определены пустым, таким образом сохраняя состояние потока и GIL манипуляции.

Таким образом, вы просто не должны приобретать GIL (и не должны), пока после того, как вы явно выпустили его (в идеале с этой макрокоманды) и должны взаимодействовать с Python в любом случае снова. (В тех случаях, когда документы говорят «некоторые блокирующие операции ввода-вывода», на самом деле это может быть любая долговременная операция без какого-либо взаимодействия с Python).

+0

Я наконец нашел обходное решение, которое искал. если (_PyThreadState_Current == NULL) { состояние = PyGILState_Ensure() } ... PyGILState_Release (состояние) мне нужно зарегистрировать поток в Python, это, кажется, работает хорошо. В настоящее время тестирование исправления ... – Alex