2016-03-30 32 views
2

ここでは、FileUtilクラスを安全なファイルIOハンドラにするためのサンプルコードを示します。(C#)ファイルの読み取り/書き込みスレッドセーフ(およびパフォーマンスを考慮する)

public static class FileUtil { 
    private static ConcurrentDictionary<string, ReaderWriterLock> s_locks = new ConcurrentDictionary<string, ReaderWriterLock>(); 

    public static string ReadFile(string path) { 
     var rwLock = s_locks.GetOrAdd(path, new ReaderWriterLock()); 
     rwLock.AcquireReaderLock(1000); 
     string data = File.ReadAllText(path); 
     rwLock.ReleaseReaderLock(); 
     return data; 
    } 

    public static void WriteFile(string path, string data) { 
     var rwLock = s_locks.GetOrAdd(path, new ReaderWriterLock()); 
     rwLock.AcquireWriterLock(1000); 
     using (StreamWriter sw = new StreamWriter(path, true)) { 
      sw.Write(data);    
     } 
     rwLock.ReleaseWriterLock(); 
    } 
} 

uは見ての通り、私は1つのロックを使用して、すべてのファイルIOを避けるために、異なるファイルごとに異なるロックを保持同時dicionaryを作成しました。私の実装は正しいですか?

+1

テストし、 – MickyD

答えて

3

いいえ、理由はほとんどありません。

まず第一には、ファイルシステムがあなたが、あなたが特に何かを実装する必要はありませんを必要とする並行処理の種類を与えることを忘れないでください。スレッドセーフとは、リソースに同時にアクセスすることはできませんが、その使用は(非常に広い意味で)失敗することはないということに注意してください。同時実行のためにOSに依存する

1つの可能な実装は、次のとおりです。WriteFile()ため

public static string ReadFile(string path) { 
    for (int retry=0; retry < 3; ++retry) { 
     try { 
      return File.ReadAllText(path); 
     } 
     catch (IOException e) { 
      // 0x80070020 is value for ERROR_SHARING_VIOLATION 
      if (Marshal.GetHRForException(e) == 0x80070020) { 
       Thread.Sleep(1000); // Wait and try again 
       continue; 
      } 

      throw; 
     } 
    } 
} 

コードは簡単です。

このようにして、異なるプロセス間で共有違反を処理し、ファイルを開くときに宣言された共有ルールを尊重することに注意してください。 File.WriteAllText()FileShare.Readと指定されていますが、同時書き込みは許可されていませんが、同時書き込みは禁止されていますので、最新のコンテンツを読み込めない場合や、File.WriteAllText()を削除してFileStreamコンストラクタ。


少数の他の注意事項について一般的な使用法

には即値が使用されています。つまり、辞書には既に指定されたパスにReaderWriterLockが含まれていても、毎回新しいオブジェクトを作成します。ロックは、初期化中に取得されていませんが、それはまだ高価な操作です、あなたは(他のコードに!)他のオーバーロードを使用する必要があります。必要な場合にのみ作成されます。この方法ではReadWriterLock

var rwLock = s_locks.GetOrAdd(path,() => new ReaderWriterLock()); 

を。

第2のポイントはReadWriterLockで、代わりにReadWriterLockSlimを使用することもできます。これは新しい軽量のリソース効率の良いバージョンです。また、リソース取得のタイムアウト、例外のスロー時に何をすべきかを検討する必要がありますか?リトライ?

最後の使用については:1000個のファイルにこのコードを使用した後、辞書には1000個の(おそらく未使用の)オブジェクトが含まれていると思います。別のシナリオでは、それぞれの使用後に処分することを検討することがあります。

+0

を参照してくださいアドリアーノRepettiありがとうございます。あなたが正しいです。しかし、私の辞書ロックの例では、他のスレッドに敏感なリソースリーダー/ライターに役立つのでしょうか? – ineztia

+0

@ineztiaはい、私は_general_の使用についていくつかのメモを追加しました。 –

関連する問題