2009-09-15 15 views
9

ten jest kontynuacją Call Python from C++Wywołanie Py_Finalize() z C

Przy uruchamianiu programm nazywam następującą funkcję aby zainicjować tłumacza:

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

Każdy wątek tworzy własną strukturę danych i nabywa zamek z:

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

raczej proste gdy zrozumiał Gil, ale problemem jest to, że mogę dostać się wysypać podczas wywoływania Py_Finalize().

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

Wniosek jest raczej wątpliwy o Py_Finalize() (a może jestem po prostu czytać wspak) i nie jestem pewien, czy PyEval_AcquireLock() można nabyć blokadę jeśli istnieje kilka aktywnych wątków i co się dzieje, jeśli istnieją aktywne wątki, gdy wywoływana jest funkcja Py_Finalize().

Anyways, otrzymuję segfault nawet jeśli jestem pewien, że wszystkie wątki zakończeniu swojej pracy, ale tylko wtedy, gdy co najmniej jedna została utworzona. Na przykład. Wywołanie initPython(), a następnie exitPython() nie powoduje żadnego błędu.

może po prostu zignorować problem i nadzieję, że OS wie, co robi, ale ja preferuję czy mogę dowiedzieć się, co się dzieje ..

Odpowiedz

7

Tak cała sekcja jest raczej wątpliwe, ale myślę, że mam mój błąd.

Muszę zapisać PyThreadState podczas inicjalizacji interpretera i zamienić ten stan z powrotem, kiedy go skończę (nie mam pojęcia, dlaczego potrzebuję określonego ThreadState, aby zadzwonić do Finalize - czy nie każde państwo powinno działać tak samo?)

Anyways przykład jeśli inni ludzie mają ten sam problem:

PyThreadState *mainstate; 

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

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

jedyny problem polega na tym, że mogę nabyć blokadę jak każdy inny wątek, nawet jeśli nie są jeszcze wątków roboczych. API nie wspomina, co się dzieje, gdy finalizacja() jest wywoływana podczas gdy inne wątki nadal pracują. Brzmi jak doskonały przykład warunków wyścigu ..

1

Czy próbowali zakomentowanie cały „praca” done w twoich wątkach? Wymień go na zajętą ​​pętlę lub uśpienie lub coś takiego. To pomoże ci ustalić, czy to twój kod inicjalizujący/zamykający, czy coś, co faktycznie robisz w Pythonie. Być może nie jesteś konfigurowania wątki prawidłowo - istnieje wiele funkcji specyficznych wątku w C API i nie jestem pewien, które z nich trzeba zapewnić prawidłowe działanie.

+0

Skomentowałem wszystko, ale PyGILState_Ensure() i Release() i błąd nadal występuje. Jeśli je również skomentuję, nie ma problemu .. – Voo

+0

W tym przypadku, zgaduję, że jest coś w zarządzaniu wątkami, które nie jest wykonywane prawidłowo. Niestety odpowiednia strona C API ze wszystkimi funkcjami wątków nie jest oczywista, do których z tych połączeń potrzebujesz. – Kylotan

+0

"Połączenia, których potrzebujesz" przez większość czasu to 'Py_BEGIN_ALLOW_THREADS' i jego odpowiednik. Są to z kolei makra, które używają 'PyEval_SaveThread()' i jej odpowiednika. Więc gdybym pisał coś w rodzaju OP, podążałbym za tym przykładem. – Kevin

1

Też mam podobny problem podczas uruchamiania skryptów zawierających pyxhook z różnych wątków poprzez wbudowany interpreter.

Nie ma problemu, jeśli jeden skrypt uruchomiony w danym momencie. Hak jest zwalniany prawidłowo, ale jeśli dwa lub więcej skryptów działał równolegle, zahaczenie nie jest zatrzymany. Choć moje skrypty zwrócony prawidłowo i cancel() z pyxhook powrócił również prawidłowo, myślę, że nadal niektóre wątki są uruchomione związane xlib. Ten problem został rozwiązany przez utrzymywanie globalnej flagi, aby sprawdzić, czy pyxhook już działa i nie reinicjalizuje pyxhook z każdego wątku.

Teraz dotyczące Py_Finalize(), jeśli pyxhook jest ponownie zainicjowany w każdym wątku:

jeśli nie nazwać PyEval_AcquireLock() i PyThreadState_Swap() przed wywołaniem Py_Finalize() to kończy się w Linuksie, ale nie w Win32. W Win32 istnieje problem, jeśli nie przechodzę przez PyEval_AcquireLock() i PyThreadState_Swap().

Na razie tymczasowym rozwiązaniem jest dla mnie odmienne zakończenie w dwóch różnych systemach operacyjnych.