PyEval_InitThreads no Python 3: Como / quando chamá-lo? (a saga continua ad nauseam)

Basicamente parece havermassivo confusão / ambiguidade sobre quando exatamentePyEval_InitThreads() é suposto ser chamado, e o que é necessário acompanhar as chamadas de API. odocumentação oficial do Python infelizmente é muito ambíguo. Já existemmuitas perguntas no stackoverflow sobre este assunto e, na verdade, eu pessoalmente jáfez uma pergunta quase idêntica para este, então eu não ficarei particularmente surpreso se isso for fechado como duplicata; mas considere que parece não haver uma resposta definitiva para essa questão. (Infelizmente, eu não tenho Guido Van Rossum na discagem rápida.)

Em primeiro lugar, vamos definir o escopo da questão aqui:o que eu quero fazer? Bem ... Eu quero escrever um módulo de extensão do Python em C que irá:

Gerar threads de trabalho usando opthread API em CInvocar retornos de chamada Python de dentro desses encadeamentos C

Ok, então vamos começar com os próprios documentos do Python. oPython 3.2 docs dizer:

void PyEval_InitThreads ()

Inicialize e adquira o bloqueio global do intérprete. Ele deve ser chamado no thread principal antes de criar um segundo thread ou envolver-se em qualquer outra operação de thread, como PyEval_ReleaseThread (tstate). Não é necessário antes de chamar PyEval_SaveThread () ou PyEval_RestoreThread ().

Então, meu entendimento aqui é que:

Qualquer módulo de extensão C que crie threads deve chamarPyEval_InitThreads() a partir do thread principal antes de quaisquer outros threads são geradosChamandoPyEval_InitThreads bloqueia o GIL

Então, o senso comum nos diria que qualquer módulo de extensão C que cria threads deve chamarPyEval_InitThreads()e depois solte o Global Interpreter Lock. Ok, parece bastante simples. assimprima facie, tudo o que é necessário seria o seguinte código:

PyEval_InitThreads(); /* initialize threading and acquire GIL */
PyEval_ReleaseLock(); /* Release GIL */

Parece bastante fácil ... mas infelizmente, o Python 3.2 docsAlém disso diz issoPyEval_ReleaseLock foidescontinuada. Em vez disso, devemos usarPyEval_SaveThread a fim de liberar o GIL:

PyThreadState * PyEval_SaveThread ()

Libere o bloqueio global do interpretador (se ele tiver sido criado e o suporte ao thread estiver ativado) e redefina o estado do encadeamento para NULL, retornando o estado do encadeamento anterior (que não é NULL). Se o bloqueio foi criado, o segmento atual deve ter adquirido.

Er ... ok, então eu acho que um módulo de extensão C precisa dizer:

PyEval_InitThreads();
PyThreadState* st = PyEval_SaveThread();


De fato, isso é exatamente o queesta resposta stackoverflow diz. Exceto quando eu realmenteexperimentar isso na prática, o interpretador Python imediatamente seg-falha quando eu importo o módulo de extensão. Agradável.

Ok, agora estou desistindo da documentação oficial do Python e me voltando para o Google. Assim,este blog aleatório reivindicações tudo que você precisa fazer de um módulo de extensão é chamarPyEval_InitThreads(). Claro, a documentação alega quePyEval_InitThreads() adquire o GIL e, de fato, uminspeção rápida do código fonte paraPyEval_InitThreads() emceval.c revela que de fato chama a função internatake_gil(PyThreadState_GET());

assimPyEval_InitThreads() definitivamente adquire o GIL. Eu pensaria então que você precisaria absolutamente de alguma forma liberar o GIL depois de chamarPyEval_InitThreads().   Mas como? PyEval_ReleaseLock() está obsoleto ePyEval_SaveThread() apenas inexplicavelmente seg-falhas.

Ok ... então talvez por algum motivo que atualmente está além do meu entendimento, um módulo de extensão Cnão faz precisa liberar o GIL. Eu tentei isso ... e, como esperado, assim que outro thread tentar adquirir o GIL (usandoPyGILState_Ensure), o programa trava de um impasse. Então sim ... vocêRealmente precisa liberar o GIL depois de chamarPyEval_InitThreads().

Então, novamente, a questão é:Como você libera o GIL depois de chamarPyEval_InitThreads()?

E mais geralmente:o que exatamente um módulo de extensão C precisa fazer para poder invocar com segurança o código Python dos encadeamentos C do trabalhador?

questionAnswers(7)

yourAnswerToTheQuestion