Python Forum

Full Version: kill a thread
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
is there a way to kill a thread that is waiting for something (it can't check a flag)? the only answers i find are to check a flag.
If the thread is waiting for a threading.Event or a threading.Condition, you can notify the Event or the Condition. Another way is to wait with a timeout to check regularly if the thread must exit. It would help if you explain what the thread actually does.
the thread reads from a pipe from a ping process.

would it be possible to have the whole process with that thread just exit? that's all i need to do is exit. but that thread is preventing that. exiting this script will then reset the network so the pings work again. the purpose of the script is to quickly detect when a remote host can no longer be reached. the idea is N missing ping replies means it is down. then the invoking script resets it and does this, again.
maybe, if i get the process ID number, i could kill the process.
The ping command accepts a timeout parameter. Try to ping with a timeout, and if the timeout occurs check if the thread must exit.
ping's timeout does not work the way i need. it "waits for a response" (per the man page) but i need to wait for a non-response of a minimum duration (long enough to not be fooled by regular network transients).
Sometimes in the past I used a trick with select statements to add artificially a socket to a list of files in a select statement. It is used to pass a message such as «exit this thread» and breaks the select wait.

Below is an example with a subprocess that pings the local host. You may think that it is complicated for what it does, but it works! The main thread is able to terminate the child thread which reads the ping output.
import threading
import selectors
import socket
import subprocess as sp

class ExitThread(Exception):
    pass

class PingThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        
    def run(self):
        self.sel = selectors.DefaultSelector()
        self.socka, self.sockb = socket.socketpair()
        self.socka.shutdown(socket.SHUT_RD)
        self.sockb.shutdown(socket.SHUT_WR)
        self.sel.register(self.sockb, selectors.EVENT_READ, self.on_sockb)
        self.proc = sp.Popen(['ping','127.0.0.1'], stdout=sp.PIPE)
        self.sel.register(
            self.proc.stdout, selectors.EVENT_READ, self.on_ping_data)
        try:
            while True:
                events = self.sel.select()
                for key, mask in events:
                    callback = key.data
                    callback(key.fileobj, mask)
        except ExitThread:
            self.sel.unregister(self.proc.stdout)
            self.sel.unregister(self.sockb)
            self.socka.close()
            self.sockb.close()
            self.proc.terminate()
            self.proc.wait()
        
    def on_ping_data(self, ofh, mask):
        s = ofh.read1(1024)
        print('PING DATA', repr(s))
        
    def on_sockb(self, sock, mask):
        raise ExitThread

    def do_exit(self):
        self.socka.sendall(b'exit\n')
    
    
def main():
    import time
    t = PingThread()
    t.start()
    for i in range(10000):
        time.sleep(0.1)
        if i == 20:
            t.do_exit()
            print('EXIT SENT')
            t.join()
            print('THREAD EXITED')
            break
    print(f'Exiting with i = {i}')
        
if __name__ == '__main__':
    main()
Output:
λ python paillasse/pf/pingthread.py PING DATA b'PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.\n' PING DATA b'64\xc2\xa0octets de 127.0.0.1\xc2\xa0: icmp_seq=1 ttl=64 temps=0.015\xc2\xa0ms\n' PING DATA b'64\xc2\xa0octets de 127.0.0.1\xc2\xa0: icmp_seq=2 ttl=64 temps=0.042\xc2\xa0ms\n' PING DATA b'64\xc2\xa0octets de 127.0.0.1\xc2\xa0: icmp_seq=3 ttl=64 temps=0.043\xc2\xa0ms\n' EXIT SENT THREAD EXITED Exiting with i = 20
(Apr-10-2022, 08:43 PM)Skaperen Wrote: [ -> ]exiting this script will then reset the network so the pings work again. the purpose of the script is to quickly detect when a remote host can no longer be reached. the idea is N missing ping replies means it is down. then the invoking script resets it and does this, again.
In your other Thread talk about ping,and icmplib has a async_ping.
Would think that this work fine for this task.
To write some more code and make a fake server error(on our server) after 60-sec,then wait 10-sec and do a sever/ping restart.
Run also schedule threaded and async_ping(the name give it way).
from icmplib import async_ping
import asyncio
import time, os
import schedule
import threading

def server_down():
    print('Server is down restart after 10-sec')
    job = schedule.every(10).seconds.do(run_threaded, check_run1)

async def is_alive(address, count):
    host = await async_ping(address, count, interval=0.2, timeout=4)
    if host.packets_received == 4:
        print(f'{host.address} is down!')
        server_down()
    else:
        print(f'{host.address} is up!')

def check_run():
    return asyncio.run(is_alive('python-forum.io', count=4))

def check_run1():
    return asyncio.run(is_alive('python-forum.io', count=0))

def run_threaded(job_func):
    job_thread = threading.Thread(target=job_func)
    job_thread.start()

if __name__ == '__main__':
    check_run()
    schedule.every(60).seconds.do(run_threaded, check_run)
    while True:
        schedule.run_pending()
        time.sleep(1)
Output:
104.21.27.41 is down! Server is down restart after 10-sec 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is down! Server is down restart after 10-sec 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up! 104.21.27.41 is up!
Quote:maybe, if i get the process ID number, i could kill the process.
If want a example of this look this post or post.
psutil is great tool for this.
And of course don't want to check contiguous that use Cpu time,so then use it a schedule way.
(Apr-11-2022, 09:02 AM)Gribouillis Wrote: [ -> ]in the past I used a trick with select statements
it looks like i will need to use select(). i will send something (icmp, udp) that bounces back and let select() wait the full (instead of counting one second timeouts) timeout for it. at least the remote host is my own server, so i can add or configure something there if i need to (that only answers if a time-based hash is just right).
i am using a free internet service where i live. i have been using it since i moved here about five years ago. it works via wifi.

recently (Jan 1) they made some changes. there is just one name to login as for everyone and no password (i wonder how long that will be). but they added a timeout of 30 minutes. but it does not disconnect. it just deletes you routes. to get them back, disconnect from the wifi and reconnect.

i am running my own VPN between here and my server (it includes IPv6). so i can ping it and all that is seen is regular encrypted traffic.

all this effort is to detect when my wifi needs to be reset. this part in Python is just to detect when the readability is down, then exit. another script runs a loop that resets the wifi, invokes wait_for_down.py, and repeats its loop.

i'm kinda amazed i was unable to find any tool to do this kind of wait. i did find a few that would wait for a host to come up.

[далі буде]