views:

198

answers:

2
+5  Q: 

Abort a thread?

I want to implement interruptable tasks based on background threads. What is the cleanest way to implement the TTask.Stop method? How can I abort the background thread?

The code executed within the thread context is passed to the task using an anonymous method and can contain blocking calls, so I can't rely on the fact, that the Terminated flag is checked regularly from within the code.

Thanks for any input.

Using D2010 in case it matters (some things in TThread seem to have changed)

+7  A: 

There is no way to safely abort a running thread. This is true for Windows programs whether written in Delphi or not, and whether using Delphi 2010 or earlier. It's an OS limitation if you want to call it that, but actually it's a limitation of threading, as aborting a thread without making sure it is not holding locks or something like that will wreak havoc with your program.

What you can do is to call the TerminateThread() API function, which is evil. Read the list of problems and warnings in this link and see whether you still want to call it. There is no other way that works without cooperation from the task code.

mghie
+7  A: 

Isolate the job into a separate process. Depending on how you communicate with the background job, this is probably the best way of guaranteeing that you can abort it cleanly.

For example, it's probably not a good ide to use shared memory for communication; use files or pipes, or a similar mechanism that doesn't break or stall when the other end gets killed. If you use named mutexes for cross-process synchronization, be aware that there is a particular error state for these synchronization primitives: WAIT_ABANDONED is returned by WaitForSingleObject and friends if a thread (or, implicitly, process's main thread) which last held the primitive was terminated without cleanly releasing it. Basically, this means you need to use a staged transactional approach to data transfer, so that you can ignore possibly inconsistent state that was being modified at the time of the termination.

Barry Kelly
That is a good (+1) answer; cf. Python threading, where much is made of the Global Interpreter Lock which is responsible both for thread safety (good) and for all practical purposes limits multithreaded code to a single core (bad). The best solution to that problem is to not use threads, but rather processes via the multiprocessing package, and what is gained by this instant ability to scale across multiple machines, which eventually becomes necessary for large scaling anyway. Instead of worrying about thread safety, it would be better to have easy (easier) multiprocess management in Delphi.
cjrh
Semaphores don't have an "abandoned" state because they don't have any built-in notion of ownership. (As far as the OS is concerned, a thread can't "hold" a semaphore.) Only a mutex can be abandoned detectably.
Rob Kennedy
This may be a good way to implement interruptible tasks with blocking code, however I don't see how the functionality in the question (an interruptible task for anonymous methods) should be implemented like this with Delphi. There would need to be a runtime compiler, to create an executable (to be spawned as a different process) from the anonymous method, wouldn't there?
mghie
Rob, good point, I removed it. mghie - you can't interrupt a thread, so it has to be in another process. That means you can't use anonymous methods. If you need to interrupt arbitrary code reliably, the code needs to be in a different process, so it's an approach that has architectural ramifications.
Barry Kelly