Sorry for the rude tone of part of that email.

Sent from my iPhone

On 27 Jun 2019, at 23:36, Michael Foord <fuzzyman@gmail.com> wrote:



On Thu, 27 Jun 2019 at 20:53, Yonatan Zunger <zunger@humu.com> wrote:
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?)

That's precisely why thread cancellation in managed languages (like Python is) raise an exception to terminate the the thread and honour finally blocks. 




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.


This is not what is being suggested. Read about the semantics of thread killing in C# and Java. 


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:


Yet again someone who doesn't understand what is being proposed saying it isn't needed. 

Michael


(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.

Yonatan

On Thu, Jun 20, 2019 at 10:16 AM Michael Foord <fuzzyman@gmail.com> wrote:


On Thu, 20 Jun 2019 at 16:33, Guido van Rossum <guido@python.org> wrote:
On Thu, Jun 20, 2019 at 8:21 AM Michael Foord <fuzzyman@gmail.com> wrote:
> It works by raising an exception in the target thread, which the thread is free to handle (usually for cleanup and then reraise).

Sure, those are the right semantics. How does it stop blocking I/O though? Suppose the thread is waiting for a server to return a response which just isn't ever going to come, but the connection somehow is kept open by the other side?



Sorry, resending to list as well. 



It used to be on the CLR getting back control. So it couldn't handle that case. (.NET 1.1). 

It has since been improved. It still blocks on the execution of unmanaged code (or computation in a finally block handling the ThreadAbortException), but blocking IO can be interrupted:


If Abort is called on a thread that is blocked or is sleeping, the thread is interrupted and then aborted.

This SO question on the topic says:


Thread.Abort()

There are 2 things I see you could do. 1 is that if you have started this TcpListener thread from another you can simply call Thread.Abort instance method on the thread which will cause a threadabortexception to be thrown within the blocking call and walk up the stack.

Michael




--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him/his (why is my pronoun here?)
--
Michael Foord
Python Consultant, Contractor and Trainer
https://agileabstractions.com/
--
Michael Foord
Python Consultant, Contractor and Trainer
https://agileabstractions.com/