5132


「ストリームを読み取れませんでした。」というエラーが出るのですが、  
原因を特定することが出来ないので質問させていただきました。

現在クラス変数で宣言している１つのストリーム変数に対して、  
二つのマルチスレッドで、交互にストリームを生成・上書きを1秒おきに繰り返しています。  
そして、そのストリームを別スレッドで定期的にBinaryReaderで読み込んでいます。

マルチスレッドによって、常にストリーム変数にストリームが格納されている状態なので、今回のようなエラーは起こりえないと考えていますが、ランダムなタイミングで今回のエラーが発生する状況です。  
このエラーの解決方法や原因が分かる方がいましたら、ご教授をお願いします。

～大まかですがソースを載せます

[code]

    // ストリーム
    private Stream stream;
    
    public void reader()
    {
     // ストリーム生成処理呼び出し
     Thread thread_A = new Thread(new ThreadStart(A));
     thread_A.Start();
    
     while (true)
     {
       try
       {
         using (BinaryReader reader = new BinaryReader(this.stream))
         {
          　読み取り処理
         }
         reader.Close();
         Thread.Sleep(1000);
       }
       catch{
       ストリームが読み取れませんでした。
       }
     }
    
    private void A()
    {
        while (true)
        {
           // ストリーム生成処理
          thread thread_A = new Thread(new ThreadStart(B));
          thread_A.Start();
          Thread.Sleep(1000);
    
          // ストリーム生成処理
          Thread thread_B = new Thread(new ThreadStart(C));
          thread_B.Start();
          Thread.Sleep(1000);
        }
     }
    
    private void B()
    { 
       this.stream = File.Open(path, FileMode.Open, FileAccess.Read,     FileShare.ReadWrite);
    }
    private void C()
    { 
       this.stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    }
    
[/code]


CC BY-SA 3.0
2015-01-23T04:50:39.547
5130
2015-01-23T09:23:50.887
2015-01-23T09:23:50.887
7287
7626
question
c# .net
エラー：ストリームを読み取れませんでした。


BinaryReader/BinaryWriterともにスレッドセーフでは、ありません。

AとBのスレッドがあるとして、  
ABABABABAB…のような動作は、保証されません。  
ABBAABBBAA…のように順不同になります。  
つまり、処理の順番は、保証されません。

場合によっては、何らかの遅延、タイミングでデータが存在しない場合もありえます。  
このような問題を解決するには、適切に排他制御を行うことです。


CC BY-SA 3.0
2015-01-23T05:43:38.823
5132
2015-01-23T05:43:38.823
2207
5130
answer


スレッドに関しては､別の方が回答なさってるので､別の見地から

> 交互にストリームを生成・上書

と記述されておりますが、読み取り位置と書き出しの位置の調停をされておりますでしょうか？  
ストリームに追記していくのであれば、先のスレッドの動作順の問題を別にすれば問題は発生しないかもしれませんが、既存領域にランダムアクセスするのであれば、問題になるかもしれません。


CC BY-SA 3.0
2015-01-23T06:52:55.107
5136
2015-01-23T06:52:55.107
7287
5130
answer


同時書込の回避方法などは別の方にお任せするとして、率直にいうと、まず質問で意図しようとしている動作が、コードに落とされていないと感じました。そこからエラーの原因が分からなくなっていったのではないかと思います。ですので、少し整えることをして、一部回答とさせてください。

以下「 **読みだしに限った**
」コードで、できるだけ質問のコードを残しつつ、意図に沿う動きを目指しています。手元に環境がなくエアプログラミングになっているので、コンパイル通らなかったらごめんなさい。

[code]

    using System;
    using System.IO;
    using System.Threading;
    
    public class Test
    {
        public static void Main() {
            new Test().startReaders();
        }
    
        private readonly string path = @"C:\tmp\test.txt";
    
        private bool isReadersRunning = false;
    
        public void startReaders() {
            if ( isReadersRunning)
                throw new InvalidOperationException();
            isReadersRunning = true;
    
            // スレッドB 生成・開始
            Thread thread_B = new Thread(new ThreadStart(B));
            thread_B.Start();
    
            // スレッドC 生成・開始
            Thread thread_C = new Thread(new ThreadStart(C));
            thread_C.Start();
    
            // メインは10秒後に終了処理を始める
            Thread.Sleep(10000);
            isReadersRunning = false;
        }
    
        private void B() {
            while (isReadersRunning) {
                System.Console.WriteLine("B Starts");
                try {
                    using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (BinaryReader reader = new BinaryReader(stream)) {
                        // 読み取り処理
                        System.Console.WriteLine("File Being Read by B");
                    }
                } catch (Exception e) {
                    // ストリームが読み取れませんでした。
                    Console.WriteLine(e.Message);
                }
                System.Console.WriteLine("B Ends");
                // 1秒まって続行
                Thread.Sleep(1000);
            }
        }
    
        private void C() {
            while (isReadersRunning) {
                System.Console.WriteLine("C Starts");
                try {
                    using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (BinaryReader reader = new BinaryReader(stream)) {
                        // 読み取り処理
                        System.Console.WriteLine("File Being Read by C");
                    }
                } catch (Exception e) {
                    // ストリームが読み取れませんでした。
                    Console.WriteLine(e.Message);
                }
                System.Console.WriteLine("C Ends");
                // 1秒まって続行
                Thread.Sleep(1000);
            }
        }
    }
    
[/code]


CC BY-SA 3.0
2015-01-23T07:43:19.603
5144
2015-01-23T07:43:19.603
4978
5130
answer