Should [nsInputStream read:…] return if [nsInputStream close] is called by another thread?

StackOverflow https://stackoverflow.com/questions/12173765

  •  29-06-2021
  •  | 
  •  

Question

It seems to me that any NSInputStream object should pop out of its read: method if the stream is closed by another thread regardless of the other end of the socket connection. But in some cases this does not appear to be true. It seems that unless the other side first sends something at least once before on the connection, the read: method will not respond to the stream closing.

Code to open the connection:

    // Open the socket...
    CFStreamCreatePairWithSocketToHost(NULL, Host, Port, &readStream, &writeStream);

    // Create NSStream objects for our use...
    inputStream = (NSInputStream *)readStream;
    outputStream = (NSOutputStream *)writeStream;

    // take ownership of the NSStream objects...
    [inputStream retain];
    [outputStream retain];

    // open the streams....
    [inputStream open];
    [outputStream open];

Code to close the connection:

    // Close the streams...
    [inputStream close];
    [outputStream close];

    // Release ownership...
    [outputStream release];
    [inputStream release];

    // clear reference values...
    outputStream = nil;
    inputStream = nil;

In the receive thread:

-(uint8_t) GetByte
{
    uint8_t c;
    int N = [inputStream read:&c maxLength:1];
    if ( N < 1 )
        @throw [[TcpClientException alloc] init];
    return c;
}

When I go to close the stream from the main thread, the receive thread remains in the read method. Eventually it times out and crashes. Even the crash does not result in any kind of object being thrown (I tried to surround the code to catch anything (id) and got nothing).

How does one reliably force read to pop out every time the streams are to be closed?

Additionally:

I am using XCODE 4.4.1 on ML with 5.1 iPad simulator.

If I only close the inputStream and do not release or set to nil, then the problem occurs as well.

Was it helpful?

Solution

After much investigation I came across another thread here at SO that hinted at the answer, that since the local device is disconnecting there would not be any event from the connection (from the remote end point) that is passed through the read method. The idea was that since the local device was responsible for disconnecting it would know that it should not enter the read method (that there would not be anything to read). This is a bit unexpected, as the user may be disconnecting when a receiver thread is already in the read method. BUT... iOS was designed apparently not to rely upon receiver threads, but events in the run loop (which is another issue, but I don't want to get into that here). Specifically, given an event from the run loop that says there is data available, you enter the read method. Thus you never enter read and hang waiting for the first byte. This is very different than socket programming that I have done on a windows platform in the past. But all the experimenting I have done thus far indicates this is the problem. I have a solution that works now that relies upon events from the stream that come out of a run loop in a worker thread so that network traffic does not interfere with the GUI(main) thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top