Reputation: 6003
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");
}
}
}
Upvotes: 0
Views: 2359
Reputation: 700152
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;
}
}
}
Upvotes: 0
Reputation: 25601
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.
Upvotes: 1
Reputation: 17499
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");
}
}
Upvotes: 0