Scene:
You often encounter the following problems: Many io busy applications adopt multi-threading methods to solve them, but at this time you will find that the python command line does not respond to ctrl-c, and the corresponding java code has no problems:
public class Test {
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
public void run() {
long start = ();
while (true) {
try {
(1000);
} catch (Exception e) {
}
(());
if (() - start > 1000 * 100) break;
}
}
}).start();
}
}
java Test
ctrl-c will end the program
And the corresponding python code:
# -*- coding: utf-8 -*-
import time
import threading
start=()
def foreverLoop():
start=()
while 1:
(1)
print ()
if ()-start>100:
break
thread_=(target=foreverLoop)
#thread_.setDaemon(True)
thread_.start()
python
After ctrl-c does not work at all.
Immature Analysis:
First of all, setting daemon to true is definitely not possible, so I won’t explain it. When daemon is false, after importing the python thread library, threading will check whether there are threads that are not daemon after the main thread is executed. Some of them will wait and wait for the thread to end. During the main thread waiting period, all signals sent to the main thread will also be blocked. You can add the signal module to verify it in the above code:
def sigint_handler(signum,frame):
print "main-thread exit"
()
(,sigint_handler)
Pressing ctrl-c within 100 seconds does not respond. The print "main-thread exit" will appear only after the child thread is finished. It can be seen that ctrl-c is blocked.
Operations performed at the end of the main thread in threading:
_shutdown = _MainThread()._exitfunc
def _exitfunc(self):
self._Thread__stop()
t = _pickSomeNonDaemonThread()
if t:
if __debug__:
self._note("%s: waiting for other threads", self)
while t:
()
t = _pickSomeNonDaemonThread()
if __debug__:
self._note("%s: exiting", self)
self._Thread__delete()
Add to join wait for all non-daemon threads, where the source code can be viewed by itself, and wait is called again. As analyzed above, the main thread waits for a lock.
Immature solutions:
You can only set the thread to daemon to prevent the main thread from waiting and accepting the ctrl-c signal, but you cannot allow the child thread to end immediately. Then you can only use the traditional polling method and use sleep to save some CPU intermittently:
# -*- coding: utf-8 -*-
import time,signal,traceback
import sys
import threading
start=()
def foreverLoop():
start=()
while 1:
(1)
print ()
if ()-start>5:
break
thread_=(target=foreverLoop)
thread_.setDaemon(True)
thread_.start()
#The main thread waits, and the signal cannot be accepted.
#thread_.join()
def _exitCheckfunc():
print "ok"
try:
while 1:
alive=False
if thread_.isAlive():
alive=True
if not alive:
break
(1)
#In order to enable statistical time to run, you must capture KeyboardInterrupt :ctrl-c
except KeyboardInterrupt, e:
traceback.print_exc()
print "consume time :",()-start
threading._shutdown=_exitCheckfunc
Disadvantages: Polling will always waste some CPU resources, and battery.
If there is a better solution, please suggest it.
ps1: Process monitoring solution:
Use another process to receive the signal and kill the execution process.
# -*- coding: utf-8 -*-
import time,signal,traceback,os
import sys
import threading
start=()
def foreverLoop():
start=()
while 1:
(1)
print ()
if ()-start>5:
break
class Watcher:
"""this class solves two problems with multithreaded
programs in Python, (1) a signal might be delivered
to any thread (which is just a malfeature) and (2) if
the thread that gets the signal is waiting, the signal
is ignored (which is a bug).
The watcher is a concurrent process (not thread) that
waits for a signal and the process that contains the
threads. See Appendix A of The Little Book of Semaphores.
/semaphores/
I have only tested this on Linux. I would expect it to
work on the Macintosh and not work on Windows.
"""
def __init__(self):
""" Creates a child thread, which returns. The parent
thread waits for a KeyboardInterrupt and then kills
the child thread.
"""
= ()
if == 0:
return
else:
()
def watch(self):
try:
()
except KeyboardInterrupt:
# I put the capital B in KeyBoardInterrupt so I can
# tell when the Watcher gets the SIGINT
print 'KeyBoardInterrupt'
()
()
def kill(self):
try:
(, )
except OSError: pass
Watcher()
thread_=(target=foreverLoop)
thread_.start()
Note that watch() must be placed before thread creation, because the reason is unknown. . . . , otherwise it will end immediately