Generally, threads don't have a notion of non-cooperative thread termination. This is because (unlike processes) threads share address spaces, and an unexpected termination of a thread can leave memory in arbitrary and unexpected states. (For example, what if one thread was holding a mutex when it got killed?)
The POSIX threading model does include the ability to send a signal to a particular thread using pthread_kill(). What that does is cause the process' globally-registered signal handler for that signal to be invoked in that particular thread. With the default handlers, though, these tend to have process-wide effects; e.g., if you pthread_kill(tid, 15) with the default handler, it will simply kill the process. This doesn't make as much sense in the context of Python's signal handling (which is a layer on top of POSIX signal handling) so signals.pthread_kill() isn't a very useful function.
In practice (and I actually had to deal with exactly this problem in my own code just last week!) there are two approaches that tend to work:
(1) Cooperative scheduling: Your code has an explicit place within the threads where they check for abort signals and handle them appropriately. For example, if your threads are each running event listeners, you might post a "cancel" event on the main bus; or alternately, you could use a threading.Event to signal everyone to shut down.
(2) Separate address spaces: If (1) isn't possible for some reason, and you need to literally be able to kill off a process noncooperatively -- say, the purpose of your code is to be an intermediate "harness" library which runs someone else's long-running functions in a thread, and it's not possible to require all of that code to obey a cooperative protocol -- then use processes instead of threads.
In many cases, you can achieve this with built-in Python libraries like multiprocessing and ProcessPoolExecutor, and in this case, you can terminate processes simply by calling Popen.send_signal() or the like. In a few cases (e.g., if you're using gRPC, whose client library is incompatible with those for complicated reasons) you'll have to fork() and exec() yourself, typically by using the subprocess.Popen library directly.