Jump to content
aehimself

Cross-platform solution to forcefully end a thread

Recommended Posts

Hello,

 

I know it's not good and should be used as a last resort or not at all. But I still need a true, cross-platform solution to instantly kill the execution of a thread, no matter what. Since I only have Windows experience, this is what I have until now:

Uses [...]{$IF defined(MSWINDOWS)}, WinApi.Windows{$ENDIF}

[...]

{$IF defined(MSWINDOWS)}
 If Self.IsRunning Then TerminateThread(Self.Handle, 1);
{$ENDIF}

How this should be implemented on Linux and more?

 

Thanks!

Share this post


Link to post

There doesn't seem to be a similar cross platform function.

 

What is wrong with Thread.Terminate?

 

You can override SetTerminate to set your own variables on termination.

F.x. if you don't want to have a Terminated check in a tight loop, you could nil a variable you reference in the loop to raise an exception to get out of that loop.

Ugly, yes - but not much uglier than TerminateThread.

 

 

Share this post


Link to post

There's no cycle, no serial commands in my thread. It calls one method in a blackbox library (blackbox = not written by me, closed source) which can freeze or take way too long to execute. My code will not regain control for hours to be able to quit, or won't regain it at all.

This leaves me no options but to expect leaks and misbehavior and kill it with fire.

Edited by aehimself

Share this post


Link to post

Edited to library 🙂 Sorry for not using the correct terminology, since this is my first multi-platform solution I'm not familiar on how these modules are called elsewhere.

 

The original question is still valid, though.

Share this post


Link to post

I am not sufficiently versed in Android and iOS to suggest a workaround there, but for Linux, you could write a thin wrapper executable and fork to run it.  If it doesn't complete within a reasonable time, you can kill that process.

On Android and iOS I guess forking would require permissions of some sort?

Share this post


Link to post

Generally, no.

 

I don't know about each and every platform but you either cannot kill unresponsive thread from the outside (application) or you can kill it but effectively doing so will also leave application in totally unstable state.

 

So, if you need to kill the thread, you basically need to kill the application itself. 

  • Like 2

Share this post


Link to post
pthread_kill

But don't do it. It's surely not the solution to your problem.

Edited by David Heffernan
  • Thanks 1

Share this post


Link to post
49 minutes ago, aehimself said:

If Self.IsRunning Then TerminateThread(Self.Handle, 1);

I'm assuming the above is just an example to explain what you need - since if you can kill the thread from within the thread, then the thread isn't frozen and you could just exit it the normal way.

 

3 minutes ago, Dalija Prasnikar said:

if you need to kill the thread, you basically need to kill the application itself.

I completely agree. Just don't do it.

 

What you could do is signal the thread (use an event, a boolean, whatever) that it has become thread-non-grata and then just forget about it.

If the blocking call ever returns then your thread can check the signal and terminate. E.g. something like this in your TThread.Execute

procedure TMyThread.Execute;
begin
  while (not Terminated) do
  begin
    CallStuffThatMightBlockForever;
    
    if (FNotInterestedAnymore) then
      break;
  end;
end;

 

Share this post


Link to post
36 minutes ago, Anders Melander said:

What you could do is signal the thread (use an event, a boolean, whatever) that it has become thread-non-grata and then just forget about it.

If the blocking call ever returns then your thread can check the signal and terminate.

What if CallStuffThatMightBlockForever never returns?

 

Share this post


Link to post
Just now, Fr0sT.Brutal said:

What if CallStuffThatMightBlockForever never returns?

Then the thread will be killed when the application terminates.

The point is that it's better to forget about the thread, report a timeout and continue as if the thread had been forcefully terminated.

 

Of course if the thread has allocated or is blocking resources then that solution might not work.

Share this post


Link to post

 

1 hour ago, Anders Melander said:

 


procedure TMyThread.Execute;
begin
  while (not Terminated) do
  begin
    CallStuffThatMightBlockForever;
    
    if (FNotInterestedAnymore) then
      break;
  end;
end;

 

There is no cycle and - as I mentioned earlier - CallStuffThatMightBlockForever might never return, therefore the break will never trigger.

 

26 minutes ago, Anders Melander said:

Then the thread will be killed when the application terminates.

The point is that it's better to forget about the thread, report a timeout and continue as if the thread had been forcefully terminated.

 

Of course if the thread has allocated or is blocking resources then that solution might not work.

If the application terminates I'm perfectly fine with that. Before reaching this point there will be 25 thousand nagging confirmation messages. If the user says yes, and accepts that the program might quit or become unstable, I did what I could.

 

Unfortunately it does block resources. However leaving it to run also can be a solution. If it's needed again I can launch an other instance, this will only cause problems during shutdown. Unless I can detach them from the process...

 

Share this post


Link to post
14 hours ago, Anders Melander said:

The point is that it's better to forget about the thread, report a timeout and continue as if the thread had been forcefully terminated. 

Is now a good time to bring up that threads are evil? 😈

Share this post


Link to post
15 minutes ago, Joseph MItzen said:

Is now a good time to bring up that threads are evil? 😈

I strongly, strongly disagree. They introduce more problems that they solve in some implementations, true; but with correct usage they can make a sluggish UI fluent, a long running calculation finish in a fraction, or simply making the application do several calculations in parallel instead of serial. One word for all: they make a better experience and happier end-users.

 

Threads are dangerous. Not evil.

  • Like 1

Share this post


Link to post

Threads are dangerous in the same way that travel by car is dangerous.

If you prepare well, know how to drive, follow the rules and take the appropriate precautions, then you will be in control and nothing bad happens.

As always, there may be external factors that can cause problems - but that goes for code that is not executed in threads as well.

 

That said - in this case, it sounds like the third party engine has serious flaws.

  • Like 1

Share this post


Link to post
37 minutes ago, Lars Fosdal said:

That said - in this case, it sounds like the third party engine has serious flaws.

It does. But we all know the phrase - you cook with what you have 😞

  • Sad 1

Share this post


Link to post
10 hours ago, aehimself said:

They introduce more problems that they solve in some implementations, true; but with correct usage they can make a sluggish UI fluent, a long running calculation finish in a fraction, or simply making the application do several calculations in parallel instead of serial.

But processes can do all those things as well while being much less dangerous.

Share this post


Link to post
9 hours ago, Lars Fosdal said:

Threads are dangerous in the same way that travel by car is dangerous.

If you prepare well, know how to drive, follow the rules and take the appropriate precautions, then you will be in control and nothing bad happens.

I'm not sure I can agree with your optimistic outlook. Threads are inherently nondeterministic in a way that human beings are not.

 

Quote

If the next generation of programmers makes more intensive use of multithreading, then the next generation of computers will become nearly unusable.

-Edward A. Lee, "The Problem With Threads"

 

It's more like traveling on the back of a hungry crocodile. If I may quote Swizec Teller's discussion of Lee's paper because it sites a perfect example (as well as giving its own car-related analogy):


 

Quote

 

Essentially the problem is this – the core abstraction of computation is a deterministic assembly of deterministic components, but threads are inherently nondeterministic. The car analogy Lee provides is trying to compose an internal combustion engine out of a pot of iron,  hydrocarbon and oxygen molecules randomly moving according to thermal forces.

This is so bad in practice even using very strict and rigid engineering principles, doesn’t help. In early 2000 Lee started the Ptolemy Project, a project designing concurrent embedded systems. But this is also an experiment in battling threads with rigorous engineering discipline – they developed a code maturity rating system, design reviews, code reviews, nightly builds, the works. Reviewers included concurrency experts and there are regression tests with 100% code coverage.

When the system started being used in 2000 no problems were observed until a deadlock on April 26th, 2004. Just the fact they know the exact date this happened tells a lot about how rigorously engineering principles are applied. Still, a very serious problem took four years to be discovered.

 

That's not a comforting example, is it? :classic_sad: Concurrency tends to cause problems, but threads are a really dangerous practice because of the shared memory issues. Processes, the actor model, functional programming with immutable values - there are a lot of other solutions that are a lot less volatile. As Guido Van Rossum pointed out several years ago, threads were never even originally intended for parallel computation! Unfortunately, a lot of developers continue to equate concurrency with threads. As Mark Summerfield puts it,

 

Quote

 

 Mid-Level Concurrency: This is concurrency that does not use any explicit atomic operations but does use explicit locks. This is the level of concurrency that most languages support..... This level of concurrency support is commonly used by application programmers, since it is often all that is available.

High-Level Concurrency: This is concurrency where there are no explicit atomic operations and no explicit locks. (Locking and atomic operations may well occur under the hood, but we don’t have to concern ourselves with them.) Some modern languages are beginning to support high-level concurrency.

 

 

Share this post


Link to post
19 minutes ago, Joseph MItzen said:

Threads are inherently nondeterministic 

What are you on about. It is perfectly possible to write code that is correct, and behaves in a deterministic fashion with threads.

 

For sure the order of scheduling and execution is not deterministic, but that doesn't mean that you can't write programs whose behaviour is deterministic. I for one make a living doing just that. 

  • Like 1

Share this post


Link to post
16 minutes ago, David Heffernan said:

What are you on about

Life, the universe, everything... and threads.

Quote

It is perfectly possible to write code that is correct, and behaves in a deterministic fashion with threads.

Lots of things are theoretically possible but incredibly difficult in practice. And should one want to do things the hardest and most error-prone way possible?

 

Quote

For sure the order of scheduling and execution is not deterministic, but that doesn't mean that you can't write programs whose behaviour is deterministic.

Professor Lee goes on with a mathematical/logical proof for two pages disagreeing with you on this. 🙂 He goes on about a theory of equivalence for sequential programs, and then...

 

Quote

Consider now whether we have a useful theory of equivalence. That is, given a pair of multithreaded programs(p1, p2)and another pair(p′1, p′2), when are these two pairs equivalent? A reasonable extension of the basic theory defines them to be equivalent if all interleavings halt for the same initial state and yield the same final state. The enormous number of possible interleavings makes it extremely difficult to reason about such equivalence except in trivial cases .... Even worse, given two programs p and p′ that are equivalent when executed according to (1), if they are executed in a multithreaded environment, we can no longer conclude that they are equivalent. In fact, we have to know about all other threads that might execute (something that may not itself be well defined), and we would have to analyze all possible interleavings. We conclude that with threads, there is no useful theory of equivalence.Still worse, implementing a multithreaded model of computation is extremely difficult. Witness,for example, the deep subtleties with the Java memory model ... where even astonishingly trivial programs produce considerable debate about their possible behaviors.The core abstraction of computation given by (1), on which all widely-used programming languages are built, emphasizes deterministic composition of deterministic components. The actions are deterministic and their sequential composition is deterministic. Sequential execution is, semantically, function composition, a neat, simple model where deterministic components compose into deterministic results.Threads, on the other hand, are wildly nondeterministic. The job of the programmer is to prune away that nondeterminism. We have, of course, developed tools to assist in the pruning. Semaphores, monitors, and more modern overlays on threads (discussed in the following section) offer the programmer ever more effective pruning. But pruning a wild mass of brambles rarely yields a satisfactory hedge.

Basically, you can't know that you've written a threaded program whose behavior is deterministic except in the most trivial of cases. The case I cited in my reply to Lars mentioned a project whose purpose was to test using rigorous engineering practices to combat threads and despite code reviews, 100% code coverage, the involvement of concurrency experts, etc. it took four years to turn up a deadlock problem. And that's why threads are evil.

 

 Even the SQLite FAQ reads....

 

Quote

6) Is SQLite threadsafe?

 

Threads are evil. Avoid them.

 

SQLite is threadsafe. We make this concession since many users choose to ignore the advice given in the previous paragraph.

I believe this idea is becoming mainstream enough in computer science (if not in application development) that we're seeing the creation of the actor model, the MapReduce algorithm, etc. as ways to implement parallelism more safely.

 

For those interested, I just started reading "Seven Concurrency Models In Seven Weeks: When Threads Unravel" and so far it's a great book. It covers threads and locks, functional programming, separating identity and state, actors, sequential processes, data parallelism, and the lambda architecture.

 

Quote

I for one make a living doing just that

Hee hee, I'll leave you with my favorite quote from Lee's paper then (in jest!)....

 

Quote

To offer a third analogy, a folk definition of insanity is to do the same thing over and over again and to expect the results to be different. By this definition, we in fact require that programmers of multithreaded systems be insane. Were they sane, they could not understand their programs.

:classic_biggrin::classic_biggrin::classic_biggrin:

Share this post


Link to post
25 minutes ago, Joseph MItzen said:

Professor Lee goes on

To paraphrase David Heffernan: That is utter nonsense and it doesn't appear that your Professor Lee has much practical knowledge about how to work safely with threads. Or maybe he's just using hyperbole to get a point across.

Under any circumstances, Quoting academia? To disprove the opinions of a professional, highly skilled and experienced developer? Really? How about some arguments based on your own knowledge and experience...

 

Many of us use threads on a daily basis and do so without wreaking havoc in the universe. If you understand the pitfalls of multi threading, know how to protect your resources, synchronize execution, understand race conditions, etc. etc., then threads are just another tool in the box. If you don't understand threading then yes, it will hurt you in a gazzilion ways you literally (and I use that word in the European sense) didn't think possible.

Share this post


Link to post
1 hour ago, Joseph MItzen said:

[...] a folk definition of insanity is to do the same thing over and over again and to expect the results to be different [...]

https://i.imgur.com/sqZE6sS.jpg

 

I hope some will get it 🙂

Edited by aehimself

Share this post


Link to post
4 hours ago, Joseph MItzen said:

Hee hee, I'll leave you with my favorite quote from Lee's paper then (in jest!)....

Maybe you are right. Maybe my multithreaded program doesn't work. 

Share this post


Link to post
On 11/14/2019 at 6:51 PM, Fr0sT.Brutal said:

What if CallStuffThatMightBlockForever never returns?

Maybe you can run two threads?

Something like your thread-1 does the loop. Upon a variable trigger or a procedure call, thread-1 runs the possibly never ending code in thread-2.

After that thread-1 checks if that thread-2 terminates in a given time limits.

If there is a timeout, your main app can provide a feedback to user and maybe an option to re-start the app or something.

Share this post


Link to post
1 hour ago, ertank said:

Maybe you can run two threads?

Something like your thread-1 does the loop. Upon a variable trigger or a procedure call, thread-1 runs the possibly never ending code in thread-2.

After that thread-1 checks if that thread-2 terminates in a given time limits.

If there is a timeout, your main app can provide a feedback to user and maybe an option to re-start the app or something.

This seems to be over-complication for me. Basically, this is somewhat what happens, only with thread 1 being the main (VCL) thread.

 

Based on the comments above it seems on Linux there's a high chance (almost certain?) that the app will quit. On Windows it leaks memory and there's a slight chance of further misbehavior - although I could not induce a case like this myself. At the end of the day, if the app is most likely to stop it's better to try to kill the thread first imo. With the 25 prior confirmations, of course 🙂

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×