tags:

views:

300

answers:

3

This is a network stream problem but i simplified test case to Console input: i started a thread ehich waits 2 seconds and closes the stream reader. But after closing stream/stream reader. While loop still waits for sr.ReadLine() method. i wan't to make it exit loop automatically when closes the stream/stream reader.

i tried also the thread safe version of Stream Reader; TextReader.synchronized. But the result is the same.

using System;
using System.IO;
using System.Threading;

namespace StreamReaderTest {
  class Program {
    static void Main(string[] args) {
      new Program();
    }

    private StreamReader sr;

    public Program() {
      sr = new StreamReader(Console.OpenStandardInput());

      new Thread(new ThreadStart(this.Close)).Start(); ;     

      string line;
      while ((line = sr.ReadLine()) != null) {
         Console.WriteLine(line);
      }
    }

    public void Close() {
      Thread.Sleep(2000);
      sr.Close();
      Console.WriteLine("Stream Closed");
    }
  }
}
A: 

Encapsulate the stream operations in a class, so that you can easily synchronise the methods to make them thread safe and make the ReadLine notice the closed state:

using System;
using System.IO;
using System.Threading;

namespace StreamReaderTest {

  class SynchronizedReader {

    private StreamReader _reader;
    private object _sync;

    public SynchronizedReader(Stream s) {
      _reader = new StreamReader(s);
      _sync = new object();
    }

    public string ReadLine() {
      lock (_sync) {
        if (_reader == null) return null;
        return _reader.ReadLine();
      }
    }

    public void Close() {
      lock (_sync) {
        _reader.Close();
        _reader = null;
      }
    }

  }

  class Program {

    static void Main(string[] args) {
      new Program();
    }

    private SynchronizedReader reader;

    public Program() {
      reader = new SynchronizedReader(Console.OpenStandardInput());

      new Thread(new ThreadStart(this.Close)).Start();

      string line;
      while ((line = reader.ReadLine()) != null) {
         Console.WriteLine(line);
      }
    }

    public void Close() {
      Thread.Sleep(2000);
      reader.Close();
      Console.WriteLine("Stream Closed");
    }
  }

}

To prevent the blocking that the ReadLine method can do while waiting for a complete line, you might want to read a character at a time from the stream instead. Note that you would have to check the closed status inside the loop that reads the characters:

class SynchronizedReader {

  private Stream _stream;
  private object _sync;

  public SynchronizedReader(Stream s) {
    _stream = s;
    _sync = new object();
  }

  public string ReadLine() {
    lock (_sync) {
      StringBuilder line = new StringBuilder();
      while (true) {
        if (_stream == null) return null;
        int c = _stream.ReadByte();
        switch (c) {
          case 10: break;
          case 13:
          case -1: return line.ToString();
          default: line.Append((char)c);
        }
      }
    }
  }

  public void Close() {
    lock (_sync) {
      _stream.Close();
      _stream = null;
    }
  }

}
Guffa
Yes, but reader still waits for an additional "enter character".
Fırat KÜÇÜK
@Fırat: Yes, the ReadLine method can block the stream if the line is not complete. You would have to read a character at a time to circumvent that.
Guffa
@Guffa: I tried it is the same. I Used Stream.readByte() method.
Fırat KÜÇÜK
@Fırat: How did you implement it? I added an example above.
Guffa
A: 

Will this work for you?

class Program
{
    static void Main(string[] args)
    {
        new Program();
    }

    private StreamReader sr;
    private bool forcefullyClose = false;

    public Program()
    {

        new Thread(new ThreadStart(this.Close)).Start(); ;

        using (sr = new StreamReader(Console.OpenStandardInput()))
        {
            string line;
            while (!forcefullyClose && (line = sr.ReadLine()) != null)
            {
                Console.WriteLine(line);
            }
        }        
    }

    public void Close()
    {
        Thread.Sleep(5000);
        forcefullyClose = true;
        Console.WriteLine("Stream Closed");
    }
}
Amby
No sorry. The same situation.
Fırat KÜÇÜK
A: 

In the console example, you may be able to use Peek to check if a character is available. For a network stream, you may be able to use Length to check if any input is available. If you don't want it to block, never read without input already pending.

BlueMonkMN