20

Sto incorporando l'interprete Python in un programma C. Tuttavia, potrebbe accadere che durante l'esecuzione di alcuni script Python tramite PyRun_SimpleString() verrà eseguito in loop infinito o eseguito troppo a lungo. Considerare PyRun_SimpleString("while 1: pass"); Nell'impedire che il programma principale blocchi, pensavo di poter eseguire l'interprete in una discussione.Arresto di Python incorporato

Come si interrompe l'esecuzione dello script python nell'interprete incorporato in esecuzione in una discussione senza uccidere l'intero processo?

È possibile passare un'eccezione all'interprete? Dovrei avvolgere lo script con qualche altro script che ascolterà i segnali?

PS: ho potuto eseguire il pitone in un processo separato, ma questo non è quello che voglio - meno che non sia l'ultima risorsa ...


Aggiornamento:

Quindi, funziona ora Grazie Denis Otkidach, ancora una volta!

Se vedo bene, devi fare due cose: dire all'interprete di fermarsi e return -1 nello stesso thread in cui PyRun_SimpleString() è in esecuzione.

Per interrompere, si hanno alcune possibilità: PyErr_SetString(PyExc_KeyboardInterrupt, "...") o PyErr_SetInterrupt() - il primo potrebbe lasciare Python eseguendo qualche altra istruzione e poi si ferma, il successivo arresta immediatamente l'esecuzione.

Per return -1 si utilizza Py_AddPendingCall() per inserire una chiamata di funzione nell'esecuzione Python. I documenti lo menzionano dalla versione 2.7 e 3.1 ma funziona anche su Python precedenti (2.6 qui). Da 2.7 e 3.1 dovrebbe anche essere thread-safe, nel senso che puoi chiamarlo senza acquisire GIL (?).

Così si potrebbe riscrivere l'esempio sotto:

int quit() { 
    PyErr_SetInterrupt(); 
    return -1; 
} 

risposta

10

È possibile utilizzare Py_AddPendingCall() per aggiungere un'eccezione di funzione da richiamare nell'intervallo di controllo successivo (consultare i documenti su sys.setcheckinterval() per ulteriori informazioni). Ecco un esempio con Py_Exit() chiamata (che fa lavori per me, ma probabilmente non è quello che serve), sostituirlo con Py_Finalize() o uno dei PyErr_Set*():

int quit(void *) { 
    Py_Exit(0); 
} 


PyGILState_STATE state = PyGILState_Ensure(); 
Py_AddPendingCall(&quit, NULL); 
PyGILState_Release(state); 

questo dovrebbe essere sufficiente per qualsiasi codice puro-python. Ma nota che alcune funzioni C possono essere eseguite per un po 'come una singola operazione (c'era un esempio con la ricerca regexp di lunga esecuzione, ma non sono sicuro che sia ancora rilevante).

+0

Questo look * molto * interessante ma non lo è per il nuovissimo Python? (L'alfa 2,7 è uscito proprio oggi.) Tuttavia, potrei effettuare l'aggiornamento a Python 3.1 - ma quale? Quale funzione dovrei registrare tramite 'Py_AddPendingCall()'? 'PyErr_SetString()'? 'Py_Exit()'? 'Py_Finalize()'? –

+0

Py_AddPendingCall esiste almeno da python 2.0 (definito in ceval.h).Ho aggiunto un codice di esempio alla mia risposta. –

+0

Grazie! Funziona! –

1

Bene l'interprete Python dovrebbe essere in esecuzione in un thread separato dal programma embedding o sarà semplicemente non avere la possibilità di interrompere l'interprete.

In questo caso, è possibile utilizzare una delle chiamate di eccezioni API Python per attivare un'eccezione nell'interprete? Vedi Python C API Exceptions

Problemi correlati