Het artikel onderzoekt de veiligheid van het gebruik van de print-functie binnen een Python signal handler. Hoewel CPython signal handlers op een veilige manier afhandelt door ze uit te stellen tot de interpreter in een consistente staat is, zijn deze handlers wel re-entrant.
Via een stress-test waarbij kort achter elkaar veel signalen (SIGUSR1) worden verstuurd, laat de auteur zien dat dit kan leiden tot een RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>.
Conclusie: Hoewel dit scenario in de praktijk zeer onwaarschijnlijk is, dient het als een technische waarschuwing. De auteur adviseert om over het algemeen geen niet-triviaal werk uit te voeren in een signal handler.
Is het veilig om print aan te roepen in een Python signal handler?
We hebben ook geleerd dat Python signal handlers onverwacht re-entrant zijn: als er een signaal binnenkomt terwijl een Python signal handler wordt uitgevoerd, kan de signal handler opnieuw worden aangeroepen midden in de eerste aanroep.
Wat gebeurt er als een signal handler re-entrant wordt aangeroepen midden in een aanroep naar print? Laten we dit stress-testen door onszelf een snelle barrage aan signalen te sturen:
import os, signal, subprocess
def sighandler(_signo, _frame):
print("signal received")
signal.signal(signal.SIGUSR1, sighandler)
subprocess.run("for x in {1..50}; do kill -USR1 %s; done" % os.getpid(), shell=True)
Het uitvoeren van dit programma op mijn machine produceerde het volgende:
File "multiple_signals.py", line 6, in sighandler
print("signal received")
File "multiple_signals.py", line 6, in sighandler
print("signal received")
File "multiple_signals.py", line 6, in sighandler
print("signal received")
[Previous line repeated 2 more times]
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
Het testprogramma laat zien dat onder extreme omstandigheden het aanroepen van print in een signal handler ertoe kan leiden dat je programma crasht. Ik wil benadrukken dat dit extreme omstandigheden vereist: het is onwaarschijnlijk dat een echt programma met deze condities te maken krijgt. Zelfs dan is falen met een exception acceptabeler dan de mogelijke gevolgen van onveilige signal handlers in C, waaronder deadlock, corrupte datastructuren en stille fouten.
Ik beschouw dit dan ook als een stukje "signals trivia" en niet als een praktische overweging voor het schrijven van signal handlers – hoewel ik nog steeds afraad om niet-triviaal werk in een signal handler uit te voeren.
Is het veilig om print aan te roepen in een Python signal handler?
We hebben ook geleerd dat Python signal handlers onverwacht re-entrant zijn: als er een signaal binnenkomt terwijl een Python signal handler wordt uitgevoerd, kan de signal handler opnieuw worden aangeroepen midden in de eerste aanroep.
Wat gebeurt er als een signal handler re-entrant wordt aangeroepen midden in een aanroep naar print? Laten we dit stress-testen door onszelf een snelle barrage aan signalen te sturen:
import os, signal, subprocess
def sighandler(_signo, _frame):
print("signal received")
signal.signal(signal.SIGUSR1, sighandler)
subprocess.run("for x in {1..50}; do kill -USR1 %s; done" % os.getpid(), shell=True)
Het uitvoeren van dit programma op mijn machine produceerde het volgende:
File "multiple_signals.py", line 6, in sighandler
print("signal received")
File "multiple_signals.py", line 6, in sighandler
print("signal received")
File "multiple_signals.py", line 6, in sighandler
print("signal received")
[Previous line repeated 2 more times]
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
Het testprogramma laat zien dat onder extreme omstandigheden het aanroepen van print in een signal handler ertoe kan leiden dat je programma crasht. Ik wil benadrukken dat dit extreme omstandigheden vereist: het is onwaarschijnlijk dat een echt programma met deze condities te maken krijgt. Zelfs dan is falen met een exception acceptabeler dan de mogelijke gevolgen van onveilige signal handlers in C, waaronder deadlock, corrupte datastructuren en stille fouten.
Ik beschouw dit dan ook als een stukje "signals trivia" en niet als een praktische overweging voor het schrijven van signal handlers – hoewel ik nog steeds afraad om niet-triviaal werk in een signal handler uit te voeren.