Continuously re-spawning a stopped/killed thread

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
Hello,

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

Kind regards.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
Why not just try { ... } catch (...) { handle ... } in your thread's main method?

On Mon, Dec 14, 2020 at 2:27 AM Volkan Yazıcı via Concurrency-interest <[hidden email]> wrote:
Hello,

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

Kind regards.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
[Today while checking the mailing-list archives to share the link of my question with a friend, I noticed Martin Buchholz's response, which I could find neither in my inbox, nor in spam folders. Maybe missed during the recent Google outage?]

On Tue Dec 15 15:44:21 EST 2020 Martin Buchholz wrote:
> Why not just try { ... } catch (...) { handle ... } in your thread's main method?

That is what I had in mind initially:

try { delegate(); }
catch (ThreadDeath ...) { ... }
catch (Throwable ...) { ... }

But is this it? These sort of blacklists always make me nervous. I did not know about ThreadDeath until a user complaint. Maybe there are more such corner cases that I need to prevent against, hence my question to this list.


On Mon, Dec 14, 2020 at 11:24 AM Volkan Yazıcı <[hidden email]> wrote:
Hello,

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

Kind regards.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list

Catching ThreadDeath is the “easy” part. But if random threads are calling Thread.stop on your thread at unknown timers then whatever your thread is trying to do can be left in a corrupt and potentially unrecoverable state. If another part of the application calls Thread.stop on your library thread then that is their stupidity – why should you care? Libraries can’t be expected to deal with a hostile environment.

 

Cheers,

David

 

From: Concurrency-interest <[hidden email]> On Behalf Of Volkan Yazici via Concurrency-interest
Sent: Friday, 18 December 2020 9:05 PM
To: [hidden email]
Subject: Re: [concurrency-interest] Continuously re-spawning a stopped/killed thread

 

[Today while checking the mailing-list archives to share the link of my question with a friend, I noticed Martin Buchholz's response, which I could find neither in my inbox, nor in spam folders. Maybe missed during the recent Google outage?]

 

On Tue Dec 15 15:44:21 EST 2020 Martin Buchholz wrote:

> Why not just try { ... } catch (...) { handle ... } in your thread's main method?

 

That is what I had in mind initially:

 

try { delegate(); }

catch (ThreadDeath ...) { ... }

catch (Throwable ...) { ... }

 

But is this it? These sort of blacklists always make me nervous. I did not know about ThreadDeath until a user complaint. Maybe there are more such corner cases that I need to prevent against, hence my question to this list.

 

 

On Mon, Dec 14, 2020 at 11:24 AM Volkan Yazıcı <[hidden email]> wrote:

Hello,

 

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

 

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

 

Kind regards.


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list

Hello,

ThreadDeath is part of the Thread#stop  mechanism. This whole concept has been deprecated for over 10 Years or so. If you "need"/"want" to implement according to the deprecated/broken Thread#stop specification : Yes you need to add a special catch Handler for ThreadDeath.

However this doesn't really make the world a much better place. Why would a user call Thread.stop? To shutdown your service. But you already have implemented a better shutdown mechanism, as has been described in the Thread.stop javadoc:

 Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running.

So adding a ThreadDeathHandler only does something if somebody is using the API wrong in the first place, and it's not really clear if that something is good.

Best Regards,

Thorsten


Am 18/12/2020 um 12:05 schrieb Volkan Yazıcı via Concurrency-interest:
[Today while checking the mailing-list archives to share the link of my question with a friend, I noticed Martin Buchholz's response, which I could find neither in my inbox, nor in spam folders. Maybe missed during the recent Google outage?]

On Tue Dec 15 15:44:21 EST 2020 Martin Buchholz wrote:
> Why not just try { ... } catch (...) { handle ... } in your thread's main method?

That is what I had in mind initially:

try { delegate(); }
catch (ThreadDeath ...) { ... }
catch (Throwable ...) { ... }

But is this it? These sort of blacklists always make me nervous. I did not know about ThreadDeath until a user complaint. Maybe there are more such corner cases that I need to prevent against, hence my question to this list.


On Mon, Dec 14, 2020 at 11:24 AM Volkan Yazıcı <[hidden email]> wrote:
Hello,

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

Kind regards.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
Indeed I don't want to deal with hostile interruptions of my thread, though I want to keep it alive.

Maybe some historical context would help to express my problem better. In the beginning, we had the following form:

try { delegate(); }
catch (Exception ...) { ... }

Though later on we figured it is pretty common to get harmless(?) Throwables that are not Exceptions, e.g., ExceptionInInitializerError. Hence I happened to change the code as follows:

try { delegate(); }
catch (Throwable ...) { ... }

Then we received the complaint regarding ThreadDeath. Rather than trying to engineer a smart try-catch block, I want to return back to the first simple form where I only catch Exceptions, but then I need to get the thread automatically respawned on unintended deaths. I thought of leveraging the "unhandled exception handler" mechanism of Executors for this automatic respawning. What do you think?

On Fri, Dec 18, 2020 at 12:45 PM Thorsten <[hidden email]> wrote:

Hello,

ThreadDeath is part of the Thread#stop  mechanism. This whole concept has been deprecated for over 10 Years or so. If you "need"/"want" to implement according to the deprecated/broken Thread#stop specification : Yes you need to add a special catch Handler for ThreadDeath.

However this doesn't really make the world a much better place. Why would a user call Thread.stop? To shutdown your service. But you already have implemented a better shutdown mechanism, as has been described in the Thread.stop javadoc:

 Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running.

So adding a ThreadDeathHandler only does something if somebody is using the API wrong in the first place, and it's not really clear if that something is good.

Best Regards,

Thorsten


Am 18/12/2020 um 12:05 schrieb Volkan Yazıcı via Concurrency-interest:
[Today while checking the mailing-list archives to share the link of my question with a friend, I noticed Martin Buchholz's response, which I could find neither in my inbox, nor in spam folders. Maybe missed during the recent Google outage?]

On Tue Dec 15 15:44:21 EST 2020 Martin Buchholz wrote:
> Why not just try { ... } catch (...) { handle ... } in your thread's main method?

That is what I had in mind initially:

try { delegate(); }
catch (ThreadDeath ...) { ... }
catch (Throwable ...) { ... }

But is this it? These sort of blacklists always make me nervous. I did not know about ThreadDeath until a user complaint. Maybe there are more such corner cases that I need to prevent against, hence my question to this list.


On Mon, Dec 14, 2020 at 11:24 AM Volkan Yazıcı <[hidden email]> wrote:
Hello,

In Log4j, we need to run a background task and keep it alive — unless JVM is stopped or our while (!stopped) condition fails after an interrupt. That is, if the task fails for some reason (e.g., by means of throwing an exception, interruption, or ThreadDeath due to Thread#stop()), it needs to be re-spawned. What is the most robust/decent way to implement this?

For the records, this is the problem I am dealing with in Log4j: https://github.com/apache/logging-log4j2/commit/56436ad2176eac000d2821690e4373f097b76670#r44892412

In a nutshell, we have a wrapper running in the background that calls Log4j Layouts to render LogEvents. Though certain layouts can do really strange things from calling Thread.currentThread().stop() to throwing an Error. These cause the wrapper thread to get killed.

I have found work arounds using uncaught exception handlers, though I couldn't be sure if this is the right way to do it.

Kind regards.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
Am 18/12/2020 um 13:15 schrieb Volkan Yazıcı:
Then we received the complaint regarding ThreadDeath. Rather than trying to engineer a smart try-catch block, I want to return back to the first simple form where I only catch Exceptions, but then I need to get the thread automatically respawned on unintended deaths. I thought of leveraging the "unhandled exception handler" mechanism of Executors for this automatic respawning. What do you think?

Hello,

I think that's overengineering for a use case that probably never existed. What is this 'complain' about?  Why does someone call Thread#stop instead of the official API and what does he expect do happen?  If you ignore ThreadDeath, your Thread might continue running. If you handle it, your Thread will die, and the rest of you library might run into problems because your Thread ist gone. If you respawn your Thread, it could be the opposite of what the user wanted, because he tried to 'stop' the tread and its immediatly back. So any 'solution' is just a hack with sideeffects.


Best Regards,

Thorsten



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Continuously re-spawning a stopped/killed thread

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
Hi,

On 12/18/20 1:15 PM, Volkan Yazıcı via Concurrency-interest wrote:
> I want to return back to the first simple form where I only catch
> Exceptions, but then I need to get the thread automatically respawned
> on unintended deaths. I thought of leveraging the "unhandled exception
> handler" mechanism of Executors for this automatic respawning. What do
> you think?


Well, the only difference between recovering from Error(s) in the same
thread and letting the thread die and spawning another thread to
continue with processing is in ThreadLocal variables. If you continue
processing in existing thread you keep them, if you spawn another
thread, you start fresh.

In both occasions the shared state (heap objects reachable from old/new
thread) is the one that might get corrupted when a thread throws
ThreadDeath as a result of another thread calling Thread.stop() on it.
The only way to avoid such corruption is for all code executing in such
thread to very carefully perform modifications to state that would still
be reachable to the thread after it recovers from ThreadDeath (or to
another thread). Each modification (assignment) must leave behind
reachable state that is valid. This is very hard to achieve if you use
common data structures that are not designed with that in mind, let
alone code that you don't control executing in that thread.
Theoretically it is doable, but nobody does that.

So I would say that if you refrain from calling Thread.stop() in your
code, you've done your part. If anybody else is using your code and
calls Thread.stop() in their code, it is their problem, not yours.


Regards, Peter




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest