Subject: Re: MzScheme - easy sample of exception handling ?
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 6 Nov 2001 12:44:11 GMT
Newsgroups: comp.lang.scheme
Message-ID: <9s8lur$62gbp$1@fido.engr.sgi.com>
Hobbyist <john@peppermind.com> wrote:
+---------------
| I want to execute numerous procedures in seperate threads. When a
| fatal error occurs in a thread, which currently is about any error, I
| would like an error message to be displayed and the thread to be
| killed.
| 
| The exception handling in MzScheme is very powerful, but also quite
| complicated -- a bit too complicated for me right now. Does anyone
| have an easy example of how to display an error and kill the thread in
| which the error has occured?
+---------------

That all happens quite automatically, actually!! The default exception
handler for a thread is one that prints an error message and kills the
thread (without disturbing other threads). For example:

	> (define (foo tid args)
	    (thread
	      (lambda ()
	        (for-each
		  (lambda (i)
		    (print* "thread #" tid " sleeping " i " seconds...")
		    (sleep i))
		  args))))
	> (for-each foo
		    '(1 2 3 4)
		    '((1 1 1 bomb) (1 2 1 die) (2 urp!) (1 1 1 1 goner)))
	> thread #4 sleeping 1 seconds...
	thread #3 sleeping 2 seconds...
	thread #2 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 2 seconds...
	thread #3 sleeping urp! seconds...
	sleep: expects argument of type <non-negative real number>; given urp!
	thread #1 sleeping 1 seconds...
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 1 seconds...
	thread #1 sleeping bomb seconds...
	sleep: expects argument of type <non-negative real number>; given bomb
	thread #4 sleeping 1 seconds...
	thread #4 sleeping goner seconds...
	sleep: expects argument of type <non-negative real number>; given goner
	thread #2 sleeping die seconds...
	sleep: expects argument of type <non-negative real number>; given die
	9876 ; <== this is hand typed
	9876
	> 

So as you see, the individual errors (which did kill the corresponding
threads) didn't prevent the other threads from continuing to run.

If you must know which thread died when, you might try wrapping the
execution of the thread with "ignore-errors", something like this:

	> (require-library "functio.ss") ; add "ignore-errors"
	> (define (foo tid args)
	    (thread
	      (lambda ()
		(let ((success #f))
		  (ignore-errors
		    (lambda ()
		      (for-each
			(lambda (i)
			  (print* "thread #" tid " sleeping " i " seconds...")
		          (sleep i))
		        args)
		      (set! success #t)))
		  (unless success
		    (print* "thread #" tid " died!!"))))))
	> (for-each foo
		    '(1 2 3 4)
		    '((1 1 1 bomb) (1 2 1 die) (2 urp!) (1 1 1 1 goner)))
	> thread #4 sleeping 1 seconds...
	thread #3 sleeping 2 seconds...
	thread #2 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 2 seconds...
	thread #3 sleeping urp! seconds...
	thread #3 died!!
	thread #1 sleeping 1 seconds...
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 1 seconds...
	thread #1 sleeping bomb seconds...
	thread #1 died!!
	thread #4 sleeping 1 seconds...
	thread #4 sleeping goner seconds...
	thread #4 died!!
	thread #2 sleeping die seconds...
	thread #2 died!!
	1234 ; typed
	1234
	> 

But of course, now you've lost the system-supplied error message.
So I'd suggest just using the first style, if it's adequate for you,
else did a bit further into the exception system.

Actually, MzScheme's exception system isn't that hard to use,
especially if all you want to do is catch and print *all* errors:

	> (define (foo tid args)
	    (thread
	      (lambda ()
		(with-handlers (((lambda ignored #t)
				 (lambda (exn)
				  (print* "exception in thread #" tid "!!")
				  (print* (exn-message exn)))))
		  (for-each
		    (lambda (i)
		      (print* "thread #" tid " sleeping " i " seconds...")
		      (sleep i))
		    args)))))
	> (for-each foo
		    '(1 2 3 4)
		    '((1 1 1 bomb) (1 2 1 die) (2 urp!) (1 1 1 1 goner)))
	>  thread #4 sleeping 1 seconds...
	thread #3 sleeping 2 seconds...
	thread #2 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 2 seconds...
	thread #3 sleeping urp! seconds...
	exception in thread #3!!
	sleep: expects argument of type <non-negative real number>; given urp!
	thread #4 sleeping 1 seconds...
	thread #1 sleeping 1 seconds...
	thread #1 sleeping bomb seconds...
	exception in thread #1!!
	sleep: expects argument of type <non-negative real number>; given bomb
	thread #4 sleeping 1 seconds...
	thread #2 sleeping 1 seconds...
	thread #2 sleeping die seconds...
	exception in thread #2!!
	sleep: expects argument of type <non-negative real number>; given die
	thread #4 sleeping goner seconds...
	exception in thread #4!!
	sleep: expects argument of type <non-negative real number>; given goner
	(+ 1 2 3) ; <== typed
	6
	> 


-Rob

-----
Rob Warnock, 30-3-510		<rpw3@sgi.com>
SGI Network Engineering		<http://www.meer.net/~rpw3/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA

[Note: aaanalyst@sgi.com and zedwatch@sgi.com aren't for humans ]