Catching control-C

M

Michael Mossey

What is required in a python program to make sure it catches a control-
c on the command-line? Do some i/o? The OS here is Linux.

Thanks,
Mike
 
C

Chris Rebert

What is required in a python program to make sure it catches a control-
c on the command-line? Do some i/o? The OS here is Linux.

try:
#code that reads input
except KeyboardInterrupt:
#Ctrl-C was pressed

Cheers,
Chris
 
M

Michael Mossey

You can use a try/except to catch a KeyboardInterrupt exception, or  
you can trap it using the signal module:http://docs.python.org/library/signal.html

You want to trap SIGINT.

HTH
Philip

Thanks to both of you. However, my question is also about whether I
need to be doing i/o or some similar operation for my program to
notice in any shape or form that Control-C has been pressed. In the
past, I've written Python programs that go about their business
ignoring Ctrl-C. Other programs respond to it immediately by exiting.
I think the difference is that the latter programs are doing i/o. But
I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

For example, does trapping SIGINT always work, regardless of what my
process is doing?

Thanks,
Mike
 
P

Philip Semanchuk

Thanks to both of you. However, my question is also about whether I
need to be doing i/o or some similar operation for my program to
notice in any shape or form that Control-C has been pressed. In the
past, I've written Python programs that go about their business
ignoring Ctrl-C. Other programs respond to it immediately by exiting.
I think the difference is that the latter programs are doing i/o. But
I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

For example, does trapping SIGINT always work, regardless of what my
process is doing?

Hi Mike,
Sorry, I don't know the Python internals well enough to answer your
question.

Good luck
Philip
 
B

Ben Charrow

Michael said:
Thanks to both of you. However, my question is also about whether I need to
be doing i/o or some similar operation for my program to notice in any shape
or form that Control-C has been pressed.

You don't need to be doing I/O in order to raise a KeyboardIneterrupt. For
example, the following program should use up a lot of your CPU until you
hit Ctrl-C.
.... pass
....
^CTraceback (most recent call last):
In the past, I've written Python programs that go about their business
ignoring Ctrl-C.

Can you be more specific? Can you share the relevant sections of these
programs? Were these programs multi-threaded?
But I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

Strictly speaking, I don't think you can always respond to a Ctrl-C in any
shape or form. Quoting from the signal module:

Although Python signal handlers are called asynchronously as far as the Python
user is concerned, they can only occur between the "atomic" instructions of the
Python interpreter. This means that signals arriving during long calculations
implemented purely in C (such as regular expression matches on large bodies of
text) may be delayed for an arbitrary amount of time.

HTH,
Ben
 
S

Steven D'Aprano

Thanks to both of you. However, my question is also about whether I need
to be doing i/o or some similar operation for my program to notice in
any shape or form that Control-C has been pressed. In the past, I've
written Python programs that go about their business ignoring Ctrl-C.

I bet that somewhere in your code you have something like:


for x in really_big_list:
try:
long_running_process(x)
except:
continue


If that's what you're doing, stop! The correct way is:


for x in really_big_list:
try:
long_running_process(x)
except Exception:
# Let KeyboardInterrupt and SystemExit through.
continue


or even:

for x in really_big_list:
try:
long_running_process(x)
except (KeyboardInterrupt, SystemExit):
print "User requested exit... shutting down now"
cleanup()
raise
except Exception:
continue
 
S

Simon Forman

Thanks to both of you. However, my question is also about whether I
need to be doing i/o or some similar operation for my program to
notice in any shape or form that Control-C has been pressed. In the
past, I've written Python programs that go about their business
ignoring Ctrl-C. Other programs respond to it immediately by exiting.
I think the difference is that the latter programs are doing i/o. But
I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

For example, does trapping SIGINT always work, regardless of what my
process is doing?

Thanks,
Mike

Try some experiments. ;]
 
L

Lie Ryan

Michael said:
Thanks to both of you. However, my question is also about whether I
need to be doing i/o or some similar operation for my program to
notice in any shape or form that Control-C has been pressed. In the
past, I've written Python programs that go about their business
ignoring Ctrl-C. Other programs respond to it immediately by exiting.
I think the difference is that the latter programs are doing i/o. But
I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

For example, does trapping SIGINT always work, regardless of what my
process is doing?

Thanks,
Mike

Are you asking: "when would the python interpreter process
KeyboardInterrupt?"

In a multi threaded python program (where KeyboardInterrupt doesn't
always work), only the main thread can process KeyboardInterrupt; thus
the main thread must regain control before the interrupt is raised.
Normally, python will context switch (i.e. thread switch) every 100
interpreter "ticks", but when the interpreter received a SIGINT, the
interpreter will try to context switch as fast as it can (every tick) to
allow the main thread to regain control. So the answer is in
multithreaded python program: "when the main thread regains control"

In single threaded python program, the currently running thread is
always the main thread (which can handle KeyboardInterrupt). I believe
SIGINT is checked at every ticks. But SIGINT cannot interrupt atomic
operations (i.e. it cannot interrupt long operations that takes a single
tick).

An example, where python have difficulties processing KeyboardInterrupt:....foofoofoo...
because printing a string is an atomic operation

I believe a tick in python is equivalent to a single bytecode, but
please correct me if I'm wrong.
 
M

Miles Kaufmann

Are you asking: "when would the python interpreter process
KeyboardInterrupt?"
...
In single threaded python program, the currently running thread is
always the main thread (which can handle KeyboardInterrupt). I believe
SIGINT is checked at every ticks. But SIGINT cannot interrupt atomic
operations (i.e. it cannot interrupt long operations that takes a
single
tick).

Some otherwise atomic single-bytecode operations (like large integer
arithmetic) do manual checks for whether signals were raised (though
that won't help at all if the operation isn't on the main thread).
I believe a tick in python is equivalent to a single bytecode, but
please correct me if I'm wrong.

Not all opcodes qualify as a tick. In general, those opcodes that
cause control to remain in the eval loop (and not make calls to other
Python or C functions) don't qualify as ticks (but there are
exceptions, e.g. so that while True: pass is interruptible). In
Python/ceval.c: PyEval_EvalFrameEx(), those opcodes that don't end in
goto fast_next_opcode are ticks.

Please correct me if _I'm_ wrong! :)
-Miles
 
M

MCIPERF

Some otherwise atomic single-bytecode operations (like large integer  
arithmetic) do manual checks for whether signals were raised (though  
that won't help at all if the operation isn't on the main thread).


Not all opcodes qualify as a tick.  In general, those opcodes that  
cause control to remain in the eval loop (and not make calls to other  
Python or C functions) don't qualify as ticks (but there are  
exceptions, e.g. so that while True: pass is interruptible).  In  
Python/ceval.c: PyEval_EvalFrameEx(), those opcodes that don't end in  
goto fast_next_opcode are ticks.

Please correct me if _I'm_ wrong! :)
-Miles

You don't need to do I/O.

This works:

try:
process_forever()
except KeyboardInterrupt:
save critical stuff
write nice messages

I often wrap a large computational task like this, with the idea that
the exception can let me exit safely, in my case by writing restart
parameters and printing a summary pf progress to date.

Gerry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,201
Messages
2,571,049
Members
47,655
Latest member
eizareri

Latest Threads

Top