none
Stopping a Thread that is blocking on stream.read

    Question

  • Hi All,

    I'm trying to stop a thread that is blocking on a stream.read (tcpClient).  I want the thread to close when the user closes the form.  I have a method in the thread called stopThread{ mythread.Abort()}.  I create an instance of the class the thread is in and call stopThread.  The result is I can an exception that states: Object reference not set to an instance of an object.  I've just started using C# as opposed to C++ so I'm little stumped.  As far as i can tell the thread sets the object.  Is it because I created a different instance, and if so how do I get around it?  Thanks in advance.  Using Visual Studio 2010.  C# 4.0 Framework.

     


    Thursday, September 01, 2011 1:35 PM

Answers

  • It sounds like you're overthinking it. This is exactly the sort of situation where a timeout is perfect!

    stream.ReadTimeout = 100;
    
    while (Connected == 1)
    {
        try
        {
            bytes_received = stream.Read(data, 0, data.Length);
        }
        catch (IOException ex)
        {
            // Make sure the connection is cleaned up
            Connected = 0;
        }
    
        if ( (bytes_received > 0) && (Connected == 1) )
        {
            // Initialize myArgs
            OnMyEventMethod(this, myArgs);
        }    
    }
    
    

    Basically what this code does is just attempt to read from the socket. If there's no data there, it will sit for 100 milliseconds, then give up and return 0. If any data was actually read, fire off the event so it can be processed. If not, the loop will check to see if Connected still equals 1 before trying to read again. The only exception you might catch is IOException - that's the only exception that you should expect to be thrown here. Any other exception indicates that something is really wrong, and you don't want to hide that.

    To use this code, just set Connected = 1 and fire it off. At any point in time, set Connected = 0 (or anything else other than 1). Within 100 milliseconds, the stream will finish reading, fire off the event if it needs to, then shut itself down. Just make sure to put any cleanup you need (disposing objects, making sure the connection is closed, etc) after the while loop.


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by parreg Friday, September 02, 2011 12:35 PM
    Thursday, September 01, 2011 9:17 PM

All replies

  • When the excpetion is thrown in debugger you should be able to get two bits of information for debugging 1) The error message and the stack trace where it was thrown.  The stack trace then will point to the code area where the null reference is being referenced incorrectly.  Find that first and then set a breakpoint in code at line right above.  This will allow you to inspect everything needed.

    In general, lack of validating variable values prior to use is #1 cause for these types of issues.  We learn in Code Contracts that there are two key areas to validate vars prior to use.  1) On entry into method (check all parms) and 2) After a calculation which sets a new var valuable but prior to use to ensure it is not null.


    JP
    Thursday, September 01, 2011 1:54 PM
  • I just tried this. The call to the myThread.Abort in the stopThread method is null.  I am making this call after creating the instance from the form_closed event handler.  I will continue to investigate.
    Thursday, September 01, 2011 2:02 PM
  • You should (almost) never call Thread.Abort in production code.  It is almost always wrong.  It will also likely cause unexpected exceptions.

    The proper way to handle a blocking call is to use nonblocking calls instead.  A close second approach is to close the object that you are blocked on.  In this case you can close the tcp client connection and the stream will immediate throw an exception.  You can wrap the blocking call in a try-catch.  In the catch block (for the appropriate "closed the stream" exception) check to see if your app is terminating.  If so then silently ignore the exception otherwise let your app's error handling kick in.

    Michael Taylor - 9/1/2011
    http://msmvps.com/blogs/p3net

    Thursday, September 01, 2011 2:02 PM
    Moderator
  • Best way to stop it, is that the method you called in the new Thread comes to an end. Even if claling Join() method (which stops the thread), it will wait until the method isnt over.

    So make sure the method ends.

    Example:

    void SomeMethod()
    {
       Thread t = new Thread(new ThreadStart(NewMethod));
       t.Start;
       
       //wait here that method ends...
       t.Join();
       //when code come here, you know thread has come to an end, so you can kiil it some how
        t = null;
    }
    
    void NewMethod()
    {
        //something to do here...
        Thread.Sleep(2000);
    }
    



    Mitja
    Thursday, September 01, 2011 2:07 PM
  • There does not seem to be an obvious way to keep the socket from blocking like in C++.  Any help in the regard would be appreciated.
    Thursday, September 01, 2011 2:18 PM
  • The thread won't end in the scenario that the thread does not get a command across the tcpClient interface.  So it just sits there blocking until a command comes in.

    If the user is unaware of this and closes the application...and the thread continues on block.

    Thursday, September 01, 2011 2:20 PM
  • And that's the point, if you have a blocking call in another thread you can't do anything but wait for it to take a breath, when it does, then you can handle things.  Simply aborting is not proper way to go as was mentioned earlier.
    JP
    Thursday, September 01, 2011 2:24 PM
  • I would like to do that, however I'm dependent upon the stream.read to handle incoming commands.  I don't know when those commands will occur so I can't time out.  When the thread gets a command it does its thing and waits for another.  I'm using the blocking nature of stream.read to listen.  I put it in it's own thread so as not to use cpu time waiting.  Why is it that if I the "stop debugging"  (shift F5) does what I want and kills the thread.  Is there anyway to utilize this feature?

    Thursday, September 01, 2011 2:33 PM
  • Ok I'm going to use the stream.BeginRead instead of the stream.Read which does not block and exit the thread conditionally.  Thanks.
    Thursday, September 01, 2011 2:49 PM
  • Perfect, and the right way to go.  Should really matter right?  User doesn't care any longer.
    JP
    Thursday, September 01, 2011 3:12 PM
  • What kind of stream are you using that Stream.Read() is a blocking call?
    Thursday, September 01, 2011 5:33 PM
  • This is what the code looks like.

     static TcpClient cmdClient = new System.Net.Sockets.TcpClient();       
     static NetworkStream cmdStream;

    Thursday, September 01, 2011 5:36 PM
  • It's synchronous, but not blocking, in that it doesn't wait for the requested number of bytes.  What's the maximum time it could take to read a full buffer.  It seems that ending the thread is being taken care of for you.
    Thursday, September 01, 2011 5:42 PM
  • It is true it will exit the thread when a command arrives.  However if the command does not arrive it will block (not execute the next statement).  If a user terminates the application the thread is still active.  That is why I switched to stream.BeginRead.  I was improperly using the stream.Read.
    Thursday, September 01, 2011 5:47 PM
  • Not sure how adding another thread corrects your problem.  How do you terminate the new thead?
    Thursday, September 01, 2011 6:29 PM
  • The thread "loops" on stream.BeginRead, each time testing if the tcp connection is still there.  If it gets a a valid command it raises an event.  If the connection is lost it will leave the loop and return thus ending the thread.  When the user closes the form...the event will close the stream and the socket.  I will indicated to the thread via property methods that the connection is now lost.  I also figured out another way of doing it using the synchronous read and returning from the thread when bytes read are equal to zero.  I'm going to use the latter.

    Thursday, September 01, 2011 6:41 PM
  • I think you might be misunderstanding - in fact, a lot of people misunderstand this issue. Despite popular opinion, Stream.BeginRead() is still a "blocking" call, in that it still sits and waits to receive some input. The real difference is that it does this waiting in a separate thread so your other code can continue to execute. When you call BeginRead() in a loop, you are spinning up a new thread for each iteration through the loop. This does not create a non-blocking read which just fails if no data is available, which is what it sounds like you're trying to do.

    In order to create a real non-blocking read, what you actually want to do is set Stream.ReadTimeout. Then call Stream.Read() as normal. The Read method will begin, but will only block for a maximum of Stream.ReadTimeout milliseconds before reporting a failure. Call that in a loop until you get the results you want. You'll need to adjust ReadTimeout to whatever is actually appropriate for your situation.

     

    EDIT: Another important thing to understand is the difference between foreground and background threads. Foreground threads will keep the application alive. Background threads will automatically close when the main application thread closes. This is why BeginRead appears to work - when you call BeginRead, it spins up a new background thread to listen for socket communications. Even if you spin up 1000 threads, they will all die when you close the application. Rather than going through all of the trouble making your Stream.Read non-blocking, you could take the easier route and just make your TCP listener thread a background thread by setting the IsBackground property to True.

     


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    Thursday, September 01, 2011 7:04 PM
  • Thanks.  That really is helpful information.  I have a problem with time outs though because nothing may happen for hours and then suddenly data or a few times and then not at all until the application is stopped.  This caused the original issue with the thread still running waiting for data. 

    I have code that does the following and it seems to work well.  It does return from the thread.  Do you see any potential issues?  Or this there a more efficient way?

              // Get Data
                try
                {
                    bytes_received = stream.Read(data, 0, data.Length);  // 20 bytes
                  
                    responseData = System.Text.Encoding.ASCII.GetString(data, 0, 20); // First Part of Message
                   
                }
                catch (System.Exception ex)
                {
                    dataRcvd = false;
                }

                while (Connected == 1)   // Client connected
                {
                    if (bytes_received > 0)
                    {
                        .....
                            // Raise the Event

                            OnMyEventMethod(this, myArgs);
                    }
                    else
                    {
                        return; // End the Thread
                    }
                    try
                    {
                        bytes_received = stream.Read(data, 0, data.Length);
                        responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes_received);

                    }
                    catch (System.Exception ex)
                    {
                        dataRcvd = false;
                    }
                }
     

    Thursday, September 01, 2011 8:58 PM
  • It sounds like you're overthinking it. This is exactly the sort of situation where a timeout is perfect!

    stream.ReadTimeout = 100;
    
    while (Connected == 1)
    {
        try
        {
            bytes_received = stream.Read(data, 0, data.Length);
        }
        catch (IOException ex)
        {
            // Make sure the connection is cleaned up
            Connected = 0;
        }
    
        if ( (bytes_received > 0) && (Connected == 1) )
        {
            // Initialize myArgs
            OnMyEventMethod(this, myArgs);
        }    
    }
    
    

    Basically what this code does is just attempt to read from the socket. If there's no data there, it will sit for 100 milliseconds, then give up and return 0. If any data was actually read, fire off the event so it can be processed. If not, the loop will check to see if Connected still equals 1 before trying to read again. The only exception you might catch is IOException - that's the only exception that you should expect to be thrown here. Any other exception indicates that something is really wrong, and you don't want to hide that.

    To use this code, just set Connected = 1 and fire it off. At any point in time, set Connected = 0 (or anything else other than 1). Within 100 milliseconds, the stream will finish reading, fire off the event if it needs to, then shut itself down. Just make sure to put any cleanup you need (disposing objects, making sure the connection is closed, etc) after the while loop.


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by parreg Friday, September 02, 2011 12:35 PM
    Thursday, September 01, 2011 9:17 PM
  • First of all Thread.Abort is quite dangerous and you should never use it. Second, since the thread has crossed over from the managed runtime to the native runtime Thread.Abort won't be able to do anything until the thread is back in managed code.

    • Edited by jader3rd Thursday, September 01, 2011 10:12 PM Asked a question that was already answered.
    Thursday, September 01, 2011 10:09 PM
  • The Read method should return if you close the Stream with the Close method.

    As for BeginRead, it is not a blocking call, the Thread that calls it won't be blocked. What should happen is that an event is created for the network device to signal when it receives information on the socket. The system has some threads will wait on those I/O events, and when one is signaled it'll submit a work item to the ThreadPool to clean up the I/O Request.

    Thursday, September 01, 2011 10:19 PM
  • "As for BeginRead, it is not a blocking call"

    If  it isn't a blocking call why would it be run on a different thread?

    Thursday, September 01, 2011 10:36 PM
  • It's not ran on a different thread. It runs start to finish on the same thread. The data from the read will come from a different thread. But BeginRead will return before that happens.
    Thursday, September 01, 2011 10:52 PM
  • Semantics. It spawns a thread for the read.  Read Tim's post.
    Thursday, September 01, 2011 11:05 PM
  • Thank you.  I thought I might have been over thinking it also.   I will try this code out. 
    Friday, September 02, 2011 12:35 PM
  • I decided not to the abort.  Thanks.
    Friday, September 02, 2011 12:36 PM
  • The scenario involves a user closing the form while the thread is active.  Even though on close form I close the stream and the client...it did not stop the thread.  I decided therefore to make sure the thread exits in another code stated above.
    Friday, September 02, 2011 12:39 PM