Python : how to stop a thread that's waiting for a .recv()

后端 未结 2 1208
生来不讨喜
生来不讨喜 2021-01-20 03:22

I have this thread running :

def run(self):
    while 1:
        msg = self.connection.recv(1024).decode()

I wish I could end this thread

相关标签:
2条回答
  • 2021-01-20 03:43

    The only really satisfactory solution I've seen for this problem is not to allow your thread to block inside recv(). Instead, set the socket to non-blocking and have the thread block inside select() instead. The advantage of blocking inside select() is that you can tell select() to return when any one of several sockets becomes ready-for-read, which brings us to the next part: as part of setting up your thread, create a second socket (either a locally-connected TCP socket e.g. as provided by socketpair, or a UDP socket listening on a port for packets from localhost). When your main thread wants your networking thread to go away, your main thread should send a byte to that socket (or in the TCP case, the main thread could just close its end of the socket-pair). That will cause select() to return ready-for-read on that socket, and when your network thread realizes that the socket is marked ready-for-read, it should respond by exiting immediately.

    The advantages of doing it that way are that it works well on all OS's, always reacts immediately (unlike a polling/timeout solution), takes up zero extra CPU cycles when the network is idle, and doesn't have any nasty side effects in multithreaded environments. The downside is that it uses up a couple of extra sockets, but that's usually not a big deal.

    0 讨论(0)
  • 2021-01-20 03:51

    Two solutions:

    1) Don't stop the thread, just allow it to die when the process exits with sys.exit()

    2) Start the thread with a "die now" flag. The Event class is specifically designed to signal one thread from another.

    The following example starts a thread, which connects to a server. Any data is handled, and if the parent signals the thread to exit, it will. As an additional safety feature we have an alarm signal to kill everything, just it case something gets out of hand.

    source

    import signal, socket, threading
    
    class MyThread(threading.Thread):
        def __init__(self, conn, event):
            super(MyThread,self).__init__()
            self.conn = conn
            self.event = event
    
        def handle_data(self):
            "process data if any"
            try:
                data = self.conn.recv(4096)
                if data:
                    print 'data:',data,len(data)
            except socket.timeout:
                print '(timeout)'
    
        def run(self):
            self.conn.settimeout(1.0)
            # exit on signal from caller
            while not self.event.is_set():
                # handle any data; continue loop after 1 second
                self.handle_data()
            print 'got event; returning to caller'
    
    
    sock = socket.create_connection( ('example.com', 80) )
    event = threading.Event()
    
    # connect to server and start connection handler
    th = MyThread(conn=sock, event=event)
    
    # watchdog: kill everything in 3 seconds
    signal.alarm(3)
    
    # after 2 seconds, tell data thread to exit 
    threading.Timer(2.0, event.set).start()
    
    # start data thread and wait for it
    th.start()
    th.join()
    

    output

    (timeout)
    (timeout)
    got event; returning to caller
    
    0 讨论(0)
提交回复
热议问题