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();
}
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.
<snip>
> 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
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
> 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. The rule about catching an exception only from the thread in which it
was thrown is absolute. You can't inject an arbitrary exception into some
other thread.
However...
> [...]
> Should I be using some other mechanism to watchdog and break the hung
> stream read?
Since you didn't post much detail in your actual code, I can't say for
sure. But generally speaking, you can cause an exception on a thread
that's blocked on an i/o operation by closing the i/o object on which the
operation was started. Depending on the type of "ssh", you could probably
call "ssh.Close()" in your "watchdog" thread to cause an exception.
Note, however, that however you do this, you have a race condition in
which your watchdog thread could wind up closing the i/o object just
_after_ it successfully returned but before it was able to assign the
result to your "response" variable. This may or may not be an issue for
you.
Finally, note that you don't get to pick the exception that's thrown. So
your code would use the exception to detect the exceptional case (which is
as it should be anyway), and the lack of an exception would indicate
success.
Pete
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
On May 9, 12:44 pm, "Peter Bromberg [C# MVP]"
<pbromb...@nospammin.yahoo.com> wrote:
> An alternative might be to make the action "timeout-able". Here's a short
> article with some sample code:http://www.eggheadcafe.com/tutorials/aspnet/847c94bf-4b8d-4a66-9ae5-5...
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.
--
Jon Skeet - <sk...@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
> Based on what Peter B referred me to I got my problem solved. Time to
> share the solution.
All due respect to the other Peter, I don't see that as a very good
solution.
The basic problem is that you never solve the problem of the call to
ReadResponse() completing. In particular, if that call really is going to
block indefinitely, you have now completely tied up a thread pool thread
for the remaining lifetime of your program. Do this too often, and you
will eventually consume your entire thread pool.
It's unfortunate that Peter B's article does not mention this serious flaw
at all. His test code may not ever exhibit the problem, because he
changed the API to eventually complete (i.e. he passes in a
"secondsToWait", which implies to me that his test code probably just
sleeps for some number of seconds before returning). But in a real world
application, where the method may not ever actually complete, it's a
problem.
There are also minor problems with the implementation you posted. Two
obvious ones are:
> [...]
> private delegate string del_StreamReader(ref SshStream ssh); //
> declare a delegate to use in the timeout
There is no need for the parameter to be defined as "ref". You aren't
changing the value of the parameter, so passing by reference is
superfluous. You seem to have added this problem all by yourself.
Also:
> [...]
> IAsyncResult sync_result = del_sr.BeginInvoke(ref ssh,
> null, new object()); //Invoke the delegate and pass parameters
You are passing "null" for the async callback parameter to BeginInvoke(),
so the third parameter -- the value passed to the callback -- is
superfluous. This problem seems to have been inherited from Peter B's
article.
Even if you did have a callback, passing a plain instance of Object would
almost always be pointless. The reason that parameter exists is to
provide the callback with some context for its processing. Since an
instance of Object has no context that's useful for most purposes, passing
one as the context doesn't make sense. (The one exception I can think of
would be using it for synchronization purposes -- i.e. using it for a
lock() or in a call to a Monitor method -- but if you need to pass a
synchronization object to your async callback, there's probably something
wrong with your design).
Without a callback, all that passing a "new object()" as the third
parameter does is exercise the garbage collector needlessly.
Obviously, it's my opinion that the above issues should be rendered moot
by a different approach to the question. However, if you insist on using
this "async delegate" approach, you should at least do it as correctly as
you can given the situation.
Pete
> [...]
>> 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
"Peter Duniho" <NpOeS...@nnowslpianmk.com> wrote in message
news:op.uawnu...@petes-computer.local...
> [...] 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.
IMHO, you should at the very least include a mention in your article that,
if the called operation is not known to eventually complete 100% of the
time, the approach may (and quite likely will, in any non-trivial
application) consume the entire thread pool.
I'm not against the solution as a specific kind of tool to address a
specific kind of problem. But it's definitely a special-purpose tool, and
readers should be warned against potential misuse.
Pete