Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2008-12

Exceptions in threads

17 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mattias Gärtner

I'm writing a unit to simplify parallel methods/procedures.

For example:
  DoParallel(@AMethod,StartIndex,EndIndex,Data);

The AMethod is executed with several threads in parallel.

What should happen when an exception occurs?
It would be nice if the exception can be transfered to the main thread. Is this possible? How?

Mattias

Reply by email

Florian Klaempfl
to Mattias Gärtner
Show quoted text 10 lines
I'm writing a unit to simplify parallel methods/procedures. For example: DoParallel(@AMethod,StartIndex,EndIndex,Data); The AMethod is executed with several threads in parallel. What should happen when an exception occurs? It would be nice if the exception can be transfered to the main thread. Is this possible? How?

See synchronize/checksynchronize implementation.

Reply by email

Luca Olivetti
to Mattias Gärtner: I'm writing a unit to simplify parallel methods/procedures. For example:…

En/na Mattias Gärtner ha escrit:

Show quoted text 8 lines
I'm writing a unit to simplify parallel methods/procedures. For example: DoParallel(@AMethod,StartIndex,EndIndex,Data); The AMethod is executed with several threads in parallel. What should happen when an exception occurs?

AFAIK any unhandled exception in a thread will cause it to silently die

It would be nice if the exception can be transfered to the main thread. Is this possible? How?

I don't know, set a flag in the thread and check it periodically from the main thread?
(Florian's suggestion does the reverse: raise in a thread an exception occurred while executing in the context of the main thread)

Bye

Luca

Reply by email

Jonas Maebe
to Luca Olivetti
Luca Olivetti wrote 9 lines
En/na Mattias Gärtner ha escrit: > I'm writing a unit to simplify parallel methods/procedures. > For example: > DoParallel(@AMethod,StartIndex,EndIndex,Data); > The AMethod is executed with several threads in parallel. > What should happen when an exception occurs? AFAIK any unhandled exception in a thread will cause it to silently die

The exception can be recovered using the tthread.fatalexception property.

Jonas

Reply by email

Mattias Gärtner
to Florian Klaempfl: See synchronize/checksynchronize implementation.

Zitat von Florian Klaempfl :

Show quoted text 13 lines
Mattias Gärtner schrieb: > I'm writing a unit to simplify parallel methods/procedures. > > For example: > DoParallel(@AMethod,StartIndex,EndIndex,Data); > > The AMethod is executed with several threads in parallel. > > What should happen when an exception occurs? > It would be nice if the exception can be transfered to the main thread. > Is this possible? How? See synchronize/checksynchronize implementation.

Sorry, I misused the term 'main thread'.

DoParallel starts AMethod with several threads in parallel and waits until all threads finished. DoParallel can be called by any thread (e.g. the main thread of the process *or* any other sub thread). Even the threads of the pool can call again DoParallel. This is only limited by the memory, as each call creates a threadgroup object.

The goal is to simplify parallelizing procedures so for the user DoParallel should work like a normal procedure call.
That's why it would be nice if the following could work:

try
  ...
  DoParallel(...);
  ...
except
end;

The exception can occur in any of the subthreads including the starting thread (which I named 'main thread', because it is the main thread of the group. Maybe I should call it 'group thread' or 'starter thread').

When an exception occurs, the group waits for all other threads of this group to finish and then the exception should happen 'as if the exception occured in the starting thread'.

Mattias

Reply by email

Mattias Gärtner
to Luca Olivetti: En/na Mattias Gärtner ha escrit: AFAIK any unhandled exception in a thread will cause it…

Zitat von Luca Olivetti :

Show quoted text 11 lines
En/na Mattias Gärtner ha escrit: > I'm writing a unit to simplify parallel methods/procedures. > > For example: > DoParallel(@AMethod,StartIndex,EndIndex,Data); > > The AMethod is executed with several threads in parallel. > > What should happen when an exception occurs? AFAIK any unhandled exception in a thread will cause it to silently die

Yes, and that should never happen. At least not for normal exceptions like out of memory, index out of bounds, io error - anything that does not corrupt the heap.
I'm catching any exception. But somehow the exception must be delegated to the group's starter thread. (which is not necessarily the process' main thread).

Show quoted text 5 lines
> It would be nice if the exception can be transfered to the main thread. > Is this possible? How? I don't know, set a flag in the thread and check it periodically from the main thread?

I do that already.
My current idea is to simply pass the exception object to the other thread and raise it there. But I'm not sure if this works always. Maybe I have to set some more RTL values to do that cleanly.

(Florian's suggestion does the reverse: raise in a thread an exception occurred while executing in the context of the main thread)

Yes, but 'synchronize' is only for the process' main thread.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gärtner: Zitat von Florian Klaempfl : Sorry, I misused the term 'main thread'. DoParallel starts…
Mattias Gärtner wrote 42 lines
Zitat von Florian Klaempfl : > Mattias Gärtner schrieb: > > I'm writing a unit to simplify parallel methods/procedures. > > > > For example: > > DoParallel(@AMethod,StartIndex,EndIndex,Data); > > > > The AMethod is executed with several threads in parallel. > > > > What should happen when an exception occurs? > > It would be nice if the exception can be transfered to the main thread. > > Is this possible? How? > > See synchronize/checksynchronize implementation. Sorry, I misused the term 'main thread'. DoParallel starts AMethod with several threads in parallel and waits until all threads finished. DoParallel can be called by any thread (e.g. the main thread of the process *or* any other sub thread). Even the threads of the pool can call again DoParallel. This is only limited by the memory, as each call creates a threadgroup object. The goal is to simplify parallelizing procedures so for the user DoParallel should work like a normal procedure call. That's why it would be nice if the following could work: try ... DoParallel(...); ... except end; The exception can occur in any of the subthreads including the starting thread (which I named 'main thread', because it is the main thread of the group. Maybe I should call it 'group thread' or 'starter thread'). When an exception occurs, the group waits for all other threads of this group to finish and then the exception should happen 'as if the exception occured in the starting thread'.

The way I uderstand threads this can never work, because then there should be a synchronization wait loop after the doparallel. Without the wait loop it'll never work, because where (at which statement) should the exception be raised ?

To make it operable, the thread should catch the exception, and then do a synchronize with a procedure that raises the exception, so that when synchronize is called, the exception is raised.

Michael.

Reply by email

Marco van de Voort
to Mattias Gärtner: Zitat von Luca Olivetti : Yes, and that should never happen. At least not for normal…

In our previous episode, Mattias G�rtner said:

Show quoted text 9 lines
> > What should happen when an exception occurs? > > AFAIK any unhandled exception in a thread will cause it to silently die Yes, and that should never happen. At least not for normal exceptions like out of memory, index out of bounds, io error - anything that does not corrupt the heap. I'm catching any exception. But somehow the exception must be delegated to the group's starter thread. (which is not necessarily the process' main thread).

I do not get this? Why is this so logical to route this to the starters thread?

There are two problems with that:
- the starter thread can be pretty much everywhere in its codepath. Not necessarily the place where the thread was started.
- It assumes some form of polling/synchronization and essentially event-driven behaviour.

Show quoted text 10 lines
> > It would be nice if the exception can be transfered to the main thread. > > Is this possible? How? > > I don't know, set a flag in the thread and check it periodically from > the main thread? I do that already. My current idea is to simply pass the exception object to the other thread and raise it there. But I'm not sure if this works always. Maybe I have to set some more RTL values to do that cleanly.

More logically, have a tthread.onexception that can handle the exception, if not already there. It can then pass it to whatever thread or subsystem necessary using custom synchronization.

> (Florian's suggestion does the reverse: raise in a thread an exception > occurred while executing in the context of the main thread) Yes, but 'synchronize' is only for the process' main thread.

Yes, and that might not be event-driven either (that is not a requirement for using tthread, only for synchronization), so IMHO that is false, and never should be default behaviour.

Reply by email

Mattias Gärtner
to Michael Van Canneyt: The way I uderstand threads this can never work, because then there should be a…

Zitat von Michael Van Canneyt :

Show quoted text 58 lines
On Thu, 11 Dec 2008, Mattias Gärtner wrote: > Zitat von Florian Klaempfl : > > > Mattias Gärtner schrieb: > > > I'm writing a unit to simplify parallel methods/procedures. > > > > > > For example: > > > DoParallel(@AMethod,StartIndex,EndIndex,Data); > > > > > > The AMethod is executed with several threads in parallel. > > > > > > What should happen when an exception occurs? > > > It would be nice if the exception can be transfered to the main thread. > > > Is this possible? How? > > > > See synchronize/checksynchronize implementation. > > Sorry, I misused the term 'main thread'. > > DoParallel starts AMethod with several threads in parallel and waits until all > threads finished. DoParallel can be called by any thread (e.g. the main thread > of the process *or* any other sub thread). Even the threads of the pool can > call again DoParallel. This is only limited by the memory, as each call creates > a threadgroup object. > > The goal is to simplify parallelizing procedures so for the user DoParallel > should work like a normal procedure call. > That's why it would be nice if the following could work: > > try > ... > DoParallel(...); > ... > except > end; > > The exception can occur in any of the subthreads including the starting thread > (which I named 'main thread', because it is the main thread of the group. Maybe > I should call it 'group thread' or 'starter thread'). > > When an exception occurs, the group waits for all other threads of this group to > finish and then the exception should happen 'as if the exception occured in the > starting thread'. The way I uderstand threads this can never work, because then there should be a synchronization wait loop after the doparallel. Without the wait loop it'll never work, because where (at which statement) should the exception be raised ?

It should be raised in the starter thread. The question is how to
- stop an exception in a thread (try..except)
- give it to another thread - the starter thread (giving the object is easy, but ...)
- continue the helper thread (this will normally free the exception object, I need a way to avoid this automatism)
- raise the exception in the starter thread (raise FetchedException).

To make it operable, the thread should catch the exception, and then do a synchronize with a procedure that raises the exception, so that when synchronize is called, the exception is raised.

I don't see how this is possible.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gärtner
Mattias Gärtner wrote 68 lines
Zitat von Michael Van Canneyt : > > > On Thu, 11 Dec 2008, Mattias Gärtner wrote: > > > Zitat von Florian Klaempfl : > > > > > Mattias Gärtner schrieb: > > > > I'm writing a unit to simplify parallel methods/procedures. > > > > > > > > For example: > > > > DoParallel(@AMethod,StartIndex,EndIndex,Data); > > > > > > > > The AMethod is executed with several threads in parallel. > > > > > > > > What should happen when an exception occurs? > > > > It would be nice if the exception can be transfered to the main thread. > > > > Is this possible? How? > > > > > > See synchronize/checksynchronize implementation. > > > > Sorry, I misused the term 'main thread'. > > > > DoParallel starts AMethod with several threads in parallel and waits until > all > > threads finished. DoParallel can be called by any thread (e.g. the main > thread > > of the process *or* any other sub thread). Even the threads of the pool can > > call again DoParallel. This is only limited by the memory, as each call > creates > > a threadgroup object. > > > > The goal is to simplify parallelizing procedures so for the user DoParallel > > should work like a normal procedure call. > > That's why it would be nice if the following could work: > > > > try > > ... > > DoParallel(...); > > ... > > except > > end; > > > > The exception can occur in any of the subthreads including the starting > thread > > (which I named 'main thread', because it is the main thread of the group. > Maybe > > I should call it 'group thread' or 'starter thread'). > > > > When an exception occurs, the group waits for all other threads of this > group to > > finish and then the exception should happen 'as if the exception occured in > the > > starting thread'. > > The way I uderstand threads this can never work, because then there should > be a synchronization wait loop after the doparallel. Without the wait loop > it'll never work, because where (at which statement) should the exception be > raised ? It should be raised in the starter thread. The question is how to - stop an exception in a thread (try..except) - give it to another thread - the starter thread (giving the object is easy, but ...) - continue the helper thread (this will normally free the exception object, I need a way to avoid this automatism) - raise the exception in the starter thread (raise FetchedException).

This is the problem: At which point should this be done ?

Can you point at the statement where it should be raised in the following code:

 try
   ...
   DoParallel(...);
   ...
 except
 end;

There is only 1 possible location: in a waitloop which should be after the DoParralel. This loop must check for the exceptions...

Michael.

Show quoted text 7 lines
> To make it operable, the thread should catch the exception, and then do a > synchronize with a procedure that raises the exception, so that when > synchronize is called, the exception is raised. I don't see how this is possible.

The whole scheme of what you try to achieve is not possible in my opinion, because it is ill-defined.

Michael.

Reply by email

Mattias Gärtner
to Marco van de Voort: In our previous episode, Mattias G�rtner said: I do not get this? Why is this so…

Zitat von Marco van de Voort :

Show quoted text 21 lines
In our previous episode, Mattias Gärtner said: > > > What should happen when an exception occurs? > > > > AFAIK any unhandled exception in a thread will cause it to silently die > > Yes, and that should never happen. At least not for normal exceptions like out > of memory, index out of bounds, io error - anything that does not corrupt the > heap. > I'm catching any exception. But somehow the exception must be delegated to the > group's starter thread. (which is not necessarily the process' main thread). I do not get this? Why is this so logical to route this to the starters thread? There are two problems with that: - the starter thread can be pretty much everywhere in its codepath. Not necessarily the place where the thread was started.

When the exception occurs, the starter is somewhere in the AMethod or in the wait loop (= somewhere in DoParallel). The starter will eventually come back to the wait loop where it checks the helper threads. The stacktrace is not that important, but the type and message of the exception object is. IMO it would be very helpful, if DoParallel could work with try..except.

- It assumes some form of polling/synchronization and essentially event-driven behaviour.

Yes.

Show quoted text 16 lines
> > > It would be nice if the exception can be transfered to the main thread. > > > Is this possible? How? > > > > I don't know, set a flag in the thread and check it periodically from > > the main thread? > > I do that already. > My current idea is to simply pass the exception object to the other thread and > raise it there. But I'm not sure if this works always. Maybe I have to set some > more RTL values to do that cleanly. More logically, have a tthread.onexception that can handle the exception, if not already there. It can then pass it to whatever thread or subsystem necessary using custom synchronization.

Yes, that is an alternative.

Show quoted text 8 lines
> > (Florian's suggestion does the reverse: raise in a thread an exception > > occurred while executing in the context of the main thread) > > Yes, but 'synchronize' is only for the process' main thread. Yes, and that might not be event-driven either (that is not a requirement for using tthread, only for synchronization), so IMHO that is false, and never should be default behaviour.

Yes.

Mattias

Reply by email

Florian Klaempfl
to Mattias Gärtner: Zitat von Michael Van Canneyt : It should be raised in the starter thread. The question…
Show quoted text 8 lines
> raised ? It should be raised in the starter thread. The question is how to - stop an exception in a thread (try..except) - give it to another thread - the starter thread (giving the object is easy, but ...) - continue the helper thread (this will normally free the exception object, I need a way to avoid this automatism)

This is why I told you to have a look how Synchronize works ;) Hint: AcquireExceptionObject/ReleaseExceptionObject which implement simply ref. counting which is respected by the exception handling code.

Reply by email

Mattias Gärtner
to Florian Klaempfl

Zitat von Florian Klaempfl :

Show quoted text 15 lines
Mattias Gärtner schrieb: >> raised ? > > It should be raised in the starter thread. The question is how to > - stop an exception in a thread (try..except) > - give it to another thread - the starter thread (giving the object is easy, but > ...) > - continue the helper thread (this will normally free the exception object, I > need a way to avoid this automatism) This is why I told you to have a look how Synchronize works ;) Hint: AcquireExceptionObject/ReleaseExceptionObject which implement simply ref. counting which is respected by the exception handling code.

Wow, I didn't know that Synchronize catches exceptions and gives them back to the calling thread.
That's exactly what I needed. :)

It works.

Mattias

Reply by email

Mattias Gärtner
to Michael Van Canneyt: This is the problem: At which point should this be done ? Can you point at the statement…

Zitat von Michael Van Canneyt :

Show quoted text 15 lines
[...] This is the problem: At which point should this be done ? Can you point at the statement where it should be raised in the following code: try ... DoParallel(...); ... except end; There is only 1 possible location: in a waitloop which should be after the DoParralel. This loop must check for the exceptions...

Not after, but at the end of DoParallel.

Mattias

Reply by email

Florian Klaempfl
to Mattias Gärtner
Show quoted text 19 lines
Zitat von Michael Van Canneyt : > [...] > This is the problem: At which point should this be done ? > > Can you point at the statement where it should be raised in the following > code: > > try > ... > DoParallel(...); > ... > except > end; > > There is only 1 possible location: in a waitloop which should be after the > DoParralel. This loop must check for the exceptions... Not after, but at the end of DoParallel.

What happens if more threads throw an exception?

Reply by email

Vincent Snijders
to Florian Klaempfl
Florian Klaempfl wrote 21 lines
Mattias Gärtner schrieb: > Zitat von Michael Van Canneyt : > >> [...] >> This is the problem: At which point should this be done ? >> >> Can you point at the statement where it should be raised in the following >> code: >> >> try >> ... >> DoParallel(...); >> ... >> except >> end; >> >> There is only 1 possible location: in a waitloop which should be after the >> DoParralel. This loop must check for the exceptions... > Not after, but at the end of DoParallel. What happens if more threads throw an exception?

A new exception is thrown, which has a List of InnerExceptions, instead of just a single InnerException ;-)

Vincent

Reply by email

Mattias Gärtner
to Vincent Snijders

Zitat von Vincent Snijders :

Show quoted text 23 lines
Florian Klaempfl schreef: > Mattias Gärtner schrieb: >> Zitat von Michael Van Canneyt : >> >>> [...] >>> This is the problem: At which point should this be done ? >>> >>> Can you point at the statement where it should be raised in the following >>> code: >>> >>> try >>> ... >>> DoParallel(...); >>> ... >>> except >>> end; >>> >>> There is only 1 possible location: in a waitloop which should be after the >>> DoParralel. This loop must check for the exceptions... >> Not after, but at the end of DoParallel. > > What happens if more threads throw an exception?

They are ignored.
If you want to handle more than the first exception then you can put a try..except into AMethod.

Note: The thread pool should simplify some parallelizations. It does not solve the problems of multi threading.

A new exception is thrown, which has a List of InnerExceptions, instead of just a single InnerException ;-)

... and a tree is created for recursive DoParallel calls. ;)

Mattias

Reply by email