PyGILState_Ensure () causando deadlock
Estou escrevendo uma extensão Python em C ++, envolvendo uma biblioteca de terceiros que não controlo. Essa biblioteca cria um encadeamento que o Python não sabe nada e, a partir desse encadeamento, chama um retorno de chamada C ++ que forneço à biblioteca. Quero que esse retorno de chamada chame uma função Python, mas recebo um impasse usando a abordagem que li nos documentos. Aqui está a minha interpretação deles.
void Wrapper::myCallback()
{
PyGILState_STATE gstate=PyGILState_Ensure();
PyObject *result=PyObject_CallMethod(_pyObj,"callback",nullptr);
if (result) Py_DECREF(result);
PyGILState_Release(gstate);
}
Meu código não faz mais nada relacionado a threads, embora eu tenha tentado várias outras coisas. Baseado emesta, por exemplo, tentei ligarPyEval_InitThreads()
, mas não é óbvio onde essa chamada deve ser feita para um ramal. Eu coloquei noPyMODINIT_FUNC
. Todas essas tentativas levaram a um impasse, travamentos ou erros fatais misteriosos do Python, por exemplo,PyEval_ReleaseThread: estado de thread incorreto.
Este é no Linux com Python 3.6.1. Alguma idéia de como posso obter esse retorno de chamada "simples" para funcionar?
Provável culpadoNão percebi que em outro encadeamento, a biblioteca estava em um loop de espera / espera aguardando o encadeamento do retorno de chamada. Nogdb
, info threads
tornou isso aparente. A única solução que posso ver é pular essas chamadas específicas para o retorno de chamada; Não vejo uma maneira de protegê-los, dado o ciclo de ocupado / espera. Nesse caso, isso é aceitável, e isso elimina o impasse.
Além disso, parece que eu também preciso chamarPyEval_InitThreads()
antes de nada disso. Em uma extensão C ++, não está claro para onde isso deve ir. Uma das respostas sugeriu fazê-lo indiretamente em Python, criando e excluindo um descartávelthreading.Thread
. Isso não parecia consertá-lo, provocando umaErro fatal do Python: take_gil: tstate NULL, o que eu acho que significa que ainda não há GIL. Meu palpite, baseado emesta e a questão a que se refere é quePyEval_InitThreads()
faz com que o thread atual se torne o thread principal do GIL. Se essa ligação for feita no segmento descartável de curta duração, talvez seja um problema. Sim, estou apenas adivinhando e gostaria de receber uma explicação de alguém que não precisa.