Threads and Exceptions

D

DaveC

I am trying to use a ssh stream reader that has no timeout method. It
simply watches the stream until an escape character appears in the
stream. It then returns the contents of the buffer. Thus, when the
server never responds to a read action (no escape character appears in
the stream), the program appears hung while the thread is waiting for
a stream character that never comes.

To solve this, I issue the stream read inside of a 'try' block with a
catch for a custom exception. Just before the call to the stream
reader, I launch a watchdog function with its own thread. The watchdog
sleeps for 3 seconds and then checks the buffer (passed in by
reference) to see if it is still empty. If it is empty, it throws the
customer exception and pulls the main thread back to the catch portion
of the try.

This sounds good, but isn't working. When the exception throws in the
watchdog thread, it is treated like an unhandled exception even tho
the thread was launched from inside of a 'try' that has an explicit
handler for that exception.

In the code snippet below, as part of my efforts to figure this out, I
have the watchdog throw an exception for either condition of the read
stream. If the stream has something in it, one exception is thrown,
and if the stream buffer is still empty another exception is thrown.
Again, both are treated as unhandled even tho the function was launced
with its own thread from inside the 'try' block.

How can I get these exceptions to be handled by the 'try' block catch
blocks?

Dave

snippet:

try
{
Thread thd_watchdog = new Thread(delegate()
{ Read_Watchdog(ref response, 200); });
thd_watchdog.Start();
response = ssh.ReadResponse();
}
catch (ExpireException)
{ return "Error opening SSH stream to " + proxyServer; }
catch (ClearException)
{ return "Success opening SSH stream to " +
proxyServer; }


private ParameterizedThreadStart Read_Watchdog(ref string response,
int i_timer)
{
Thread.Sleep(i_timer);
if (response.Length > 0)
throw new ClearException();
else
throw new ExpireException();
}
 
P

parez

This is what i noticed in a .net 1.1 app.

you have to try catch within the function that the thread executes. if
you dont have a try catch in the function then you dont get notified
about the unhandled exception.
Dont know if things have changed since then.
 
J

Jon Skeet [C# MVP]

How can I get these exceptions to be handled by the 'try' block catch
blocks?

An exception can only be caught in the thread which throws it. In
other words, if you want a particular "catch" block to execute, you
need to move that into the code executed in the other thread.

Jon
 
D

DaveC

Ouch... the whole basis of my approach is that one thread could watch
and use an exception to interrupt another thread that was not
performing well.

Could I name my main() thread and then have the watchdog thread throw
the exception on the main thread instead of its own thread?

What would the code for that even look like?

throw new Thread.Threads("main").ClearException(); //complete and
total WAG

- OR -

Should I be using some other mechanism to watchdog and break the hung
stream read?

Dave
 
P

Peter Bromberg [C# MVP]

An alternative might be to make the action "timeout-able". Here's a short
article with some sample code:
http://www.eggheadcafe.com/tutorial...e5-5b61f049019f/basics-make-any-method-c.aspx
--Peter
Ouch... the whole basis of my approach is that one thread could watch
and use an exception to interrupt another thread that was not
performing well.

Could I name my main() thread and then have the watchdog thread throw
the exception on the main thread instead of its own thread?

What would the code for that even look like?

throw new Thread.Threads("main").ClearException(); //complete and
total WAG

- OR -

Should I be using some other mechanism to watchdog and break the hung
stream read?

Dave
 
D

DaveC

Based on what Peter B referred me to I got my problem solved. Time to
share the solution.

The problem was this... the following line would never return if the
server the SshStream was attached to didn't respond with an
appropriate escape character. The SshStream class did not have
a .TimeOut() method to cope with the situation.

string response = ssh.ReadResponse();

The call needed to be made in such a way that it could timeout
gracefully. Using a delegate turned out to be the 'best' answer I
found. Here are the critical parts of the code:

private delegate string del_StreamReader(ref SshStream ssh); //
declare a delegate to use in the timeout

private string ssh_StreamReader(ref SshStream ssh) //wrap the
call that needs the timeout in a helper function
{
return ssh.ReadResponse();
}

to use in a function:

del_StreamReader del_sr = new
del_StreamReader(ssh_StreamReader); //create an instance of the
delegate
IAsyncResult sync_result = del_sr.BeginInvoke(ref ssh,
null, new object()); //Invoke the delegate and pass parameters
if (!sync_result.AsyncWaitHandle.WaitOne(200,
false)) //wait 200ms and then check to
see if delegate has finished
return "Error reading SSH stream"; //if the call
had not completed yet, treat as an error
else
response = del_sr.EndInvoke(ref ssh,sync_result); //
if the call has finished, get the results of the delegate (i.e. helper
function)

Dave

additional keywords: Tamir Tamir.sharpSsh Tamir.sharpSsh.dll sharpSsh
 
J

Jon Skeet [C# MVP]

DaveC said:
Ouch... the whole basis of my approach is that one thread could watch
and use an exception to interrupt another thread that was not
performing well.

Could I name my main() thread and then have the watchdog thread throw
the exception on the main thread instead of its own thread?

No. Don't forget that your main thread might be doing something
completely different at the time - if it was busy doing one thing, you
wouldn't want it to suddenly abort that just to report the exception,
would you?
Should I be using some other mechanism to watchdog and break the hung
stream read?

As Peter suggested, using a timeout is a good way - or you could
potentially close the stream from a different thread. I don't know the
details of how safe that is, but it's at least a possibility.
 
P

Peter Bromberg [C# MVP]

First, you are completely correct that my suggestion is far from a robust
solution. However, you might be interested to know that the reason I had to
do this was because I had a boss who insisted on running his remoting
endpoint in his VB.NET IDE in debug mode, occasionally with breakpoints set
which would of course insure that his methods never returned (DUH!). In a
case like this one, it was more politics than best practices. I leave it as
a potential (although by all accounts not reliable) alternative when one
has absolutely no control over the robustness of the remote code one is
calling.
Cheers,
Peter

Peter Duniho said:
[...]
Should I be using some other mechanism to watchdog and break the hung
stream read?

As Peter suggested, using a timeout is a good way - or you could
potentially close the stream from a different thread. I don't know the
details of how safe that is, but it's at least a possibility.

Closing an i/o object from a thread other than the one where the object is
blocking is a common technique, especially in network i/o (it's a standard
feature of all the socket implementations I've seen). The OP still hasn't
provided any detail as to which class he's actually using, but assuming
it's a built-in .NET Framework class, I expect that closing the object is
not only safe, it's the right thing to do.

As I pointed out in my other reply, the timeout implementation Peter B has
suggested has a serious problem with it. If you've got a class that
defines an API that supports timeouts, then yes...that's a great way to
go. But if I read this message thread correctly, the specific problem is
that the OP is using a class that doesn't itself support timeouts.

Of course, without knowing the actual class he's using, there's no way to
verify that.

Adding a timeout in _some_ fashion is obviously the goal here, but using
the BeginInvoke() method on a delegate instance as Peter B suggests is not
a good general-purpose way to impose a timeout on some operation. It's
probably fine for operations that you know _for sure_ will eventually
complete, and will do so in a reasonably short period of time (seconds,
maybe a few minutes depending on how often one might attempt such an
operation, and certainly not hours). But it's completely unsuitable if
you're dealing with operations that may never complete.

As is often the case, if the OP would provide actual details on what the
code is really doing, it would be a lot easier to provide good advice. So
far, we still don't know what i/o object is ultimately being used here, so
it's not really possible to tell him what the best timeout strategy might
be.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top