2009-09-15 3 views
9

Это следовать до Call Python from C++Вызов Py_Finalize() из C

При запуске программе я называю следующую функцию для инициализации интерпретатора:

void initPython(){ 
    PyEval_InitThreads(); 
    Py_Initialize(); 
    PyEval_ReleaseLock(); 
} 

Каждый поток создает свою собственную структуру данных и получает блокировку с:

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 
//call python API, process results 
PyGILState_Release(gstate); 

Скорее прямо вперед, как только вы поняли GIL, но проблема в том, что я получаю Segfault при вызове Py_Finalize().

void exitPython(){ 
    PyEval_AcquireLock(); 
    Py_Finalize(); 
} 

Ссылка весьма сомнительна о Py_Finalize() (или, может быть, я просто читал это неправильный путь), и я не уверен, что если PyEval_AcquireLock() может получить блокировку, если есть некоторые активные потоки и что происходит, если есть активные потоки, когда вызывается Py_Finalize().

В любом случае, я получаю segfault, даже если я уверен, что все потоки завершили свою работу, но только если был создан хотя бы один. Например. вызов initPython(), который следует из exitPython(), не создает ошибок.

я мог бы просто игнорировать эту проблему и надеюсь, что операционная система знает, что он делает, но я предпочитаю, если бы я мог понять, что происходит ..

ответ

7

Да, весь раздел довольно сомнительный, но я думаю, что у меня есть моя ошибка.

Мне нужно сохранить PyThreadState при инициализации интерпретатора и заменить это состояние, когда я его завершу (не знаю, зачем мне нужен конкретный ThreadState для вызова Finalize - не должно ли каждое государство работать тоже?)

в любом случае пример, если другие люди получили ту же проблему:

PyThreadState *mainstate; 

void initPython(){ 
    PyEval_InitThreads(); 
    Py_Initialize(); 
    mainstate = PyThreadState_Swap(NULL); 
    PyEval_ReleaseLock(); 
} 

void exitPython(){ 
    PyEval_AcquireLock(); 
    PyThreadState_Swap(mainstate); 
    Py_Finalize(); 
} 

Единственная проблема состоит в том, что я могу получить блокировку, как и любой другой поток, даже если есть еще нити работают. API не упоминает, что происходит, когда вызывается Finalize(), в то время как другие потоки все еще работают. Звучит как идеальный пример состояния гонки.

1

Вы пробовали закомментировать все «работу» сделаны в ваших потоках? Замените его занятым циклом или сна или что-то еще. Это поможет определить, является ли это вашим кодом инициализации/выключения, или тем, что вы на самом деле делаете с Python между ними. Возможно, вы неправильно настроили нити - в C API много функций, связанных с потоком, и я не уверен, какие из них вам нужны для обеспечения правильной работы.

+0

Я прокомментировал все, но PyGILState_Ensure() и Release(), и ошибка все еще происходит. Если я их прокомментирую, это не проблема .. – Voo

+0

В этом случае я предполагаю, что есть что-то в управлении потоками, которое не выполняется должным образом. К сожалению, соответствующая страница C API со всеми функциями потока на ней далеко не очевидна относительно того, какой из этих вызовов вам нужен. – Kylotan

+0

«Звонки вам нужны» большую часть времени - «Py_BEGIN_ALLOW_THREADS» и его коллега. Это, в свою очередь, макросы, которые используют 'PyEval_SaveThread()' и его аналог. Поэтому, если бы я писал что-то вроде OP, я бы следовал этому примеру. – Kevin

1

У меня также возникает аналогичная проблема при запуске скриптов, содержащих pyxhook из разных потоков через встроенный интерпретатор.

Нет проблем, если один скрипт работает одновременно. Крюк выпущен правильно, но если два или более скрипта работают параллельно, перехват не останавливается. Хотя мои скрипты вернулись правильно и cancel() из pyxhook также вернулись правильно, я думаю, что некоторые потоки работают, связанные с xlib. Эта проблема pyxhook, которую я решил, сохраняя глобальный флаг, чтобы посмотреть, работает ли pyxhook, а не повторно инициализировать pyxhook из каждой темы.

Теперь о Py_Finalize(), если pyxhook повторно инициализирован в каждом потоке:

, если я не называю PyEval_AcquireLock() и PyThreadState_Swap() перед вызовом Py_Finalize() она заканчивается в Linux, но не в Win32. В Win32 возникает проблема, если я не пройду через PyEval_AcquireLock() и PyThreadState_Swap().

В настоящее время временное решение для меня заключается в том, чтобы прекратить работу по-разному в двух разных ОС.