2010-01-17 6 views
0

Il s'agit d'un problème de flux de réseau mais j'ai simplifié le cas de test à l'entrée de la console: J'ai démarré un thread qui attend 2 secondes et ferme le lecteur de flux. Mais après fermeture lecteur de flux/flux. While loop attend toujours la méthode sr.ReadLine(). Je ne veux pas faire sortir la boucle automatiquement quand ferme le lecteur de flux/flux. J'ai aussi essayé la version thread-safe de Stream Reader; TextReader.synchronized. Mais le résultat est le même.Quitter la boucle While lorsque le flux est fermé?

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"); 
    } 
    } 
} 
+0

related: http://stackoverflow.com/questions/981196/how-to-know-if-a-bufferedreader-stream-is-closed –

+0

StreamReader ne devrait-il pas être sous votre contrôle total? Peut-être que cet exemple est un peu trompeur. – ziya

+1

Dans le cas du flux réseau, j'attendrais * que cela fonctionne déjà; Je * soupçonne * que les subtilités de la fermeture du flux d'entrée propres aux processus actuels peuvent porter à confusion ici? –

Répondre

0

Encapsulate les opérations de flux dans une classe, de sorte que vous pouvez facilement synchroniser les méthodes pour les rendre thread-safe et faire l'avis ReadLine l'état fermé:

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"); 
    } 
    } 

} 

Pour éviter le blocage que la La méthode ReadLine peut faire en attendant une ligne complète, vous pouvez lire un caractère à la fois à partir du flux à la place. Notez que vous devrez vérifier l'état fermé à l'intérieur de la boucle qui lit les caractères:

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; 
    } 
    } 

} 
+0

Oui, mais le lecteur attend toujours un "caractère d'entrée" supplémentaire. –

+0

@ Fırat: Oui, la méthode ReadLine peut bloquer le flux si la ligne n'est pas complète. Vous auriez à lire un personnage à la fois pour contourner cela. – Guffa

+0

J'ai essayé c'est pareil. J'ai utilisé la méthode Stream.readByte(). –

0

Cela fonctionnera pour vous?

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"); 
    } 
} 
+0

Non désolé. La même situation. –

1

Dans l'exemple de console, vous pouvez utiliser Peek pour vérifier si un caractère est disponible. Pour un flux réseau, vous pouvez utiliser Longueur pour vérifier si une entrée est disponible. Si vous ne voulez pas qu'il bloque, ne lisez jamais sans entrée déjà en attente.

Questions connexes