前提・実現したいこと
C#で、ファイルの読み書きを同時に行わせないよう排他制御としてMutexを取り入れたプログラムを実現したい。
一度の処理で複数回読み書きがある場合、その処理がすべて終わるまでファイルの読み書きを行えないようにしたい。
例)ファイルにデータを書き込む場合、既にあるデータは書き込まないようにデータをファイルから読み込んで確認してから書き込みをする。
その際に、下記の修正よりも簡単な手段があるのかを知りたい。
ここで、ファイルの読み書きを同時に行うというのは"1ファイルに対して複数の処理で同時に読み書きする"ではなく、
"ReadWriteClassを用いて複数のプロセスで同時に読み書きする"ことで、それを制限したいという意味です。(読み書きの対象が別ファイルでも制限したい)
下記例のReadWriteClassが複数のプロセスで利用されることを想定しています。
該当のソースコード
#####修正前のソースコード
- ReadWriteClass.cs
C#
1using System.Collections.Generic; 2using System.Linq; 3using System.Threading; 4using System.IO; 5 6namespace MutexSample 7{ 8 class ReadWriteClass 9 { 10 private static Mutex mutex = new Mutex(false, "sample"); 11 public T GetData<T>(string path) 12 { 13 //Jsonファイルからデータを読んでTに加工する。 14 string jsonData = File.ReadAllText(path); 15 var ret = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonData); 16 return ret; 17 } 18 19 public void CreateData(string name) 20 { 21 var newData = new DataClass { Name = name }; 22 23 mutex.WaitOne(); 24 var currentData = GetData<List<DataClass>>(""); 25 26 if (!currentData.Any((data) => data.Name.Equals(newData.Name))) 27 { 28 SaveData(""); 29 } 30 mutex.ReleaseMutex(); 31 } 32 33 public void SaveData(string path) 34 { 35 } 36 } 37}
- DataClass.cs
C#
1namespace MutexSample 2{ 3 public class DataClass 4 { 5 public string Name { get; set; } 6 } 7}
- OtherClass.cs
C#
1using System.Collections.Generic; 2 3namespace MutexSample 4{ 5 class OtherClass 6 { 7 public static void main(string[] args) 8 { 9 var rw = new ReadWriteClass(); 10 rw.GetData<List<DataClass>>(""); 11 } 12 } 13}
###修正前のソースコードにおける問題点
-
OtherClassのmain関数から、ReadWriteClassのGetData関数を呼び出しているが、GetData関数はファイルから読み込む処理が入っているものの排他制御されない。
-
GetData関数のReadAllText関数前後にMutexを利用した排他制御を書いた場合、CreateData関数を呼び出すとデッドロックが起きてしまうため書けない。
####修正後のソースコード
- ReadWriteClass.cs
C#
1using System.Collections.Generic; 2using System.Linq; 3using System.Threading; 4using System.IO; 5 6namespace MutexSample 7{ 8 class ReadWriteClass 9 { 10 private static Mutex mutex = new Mutex(false, "sample"); 11 public T GetData<T>(string path) 12 { 13 mutex.WaitOne(); 14 var ret = GetDataPrivate<T>(path); 15 mutex.ReleaseMutex(); 16 17 return ret; 18 } 19 20 private T GetDataPrivate<T>(string path) 21 { 22 string jsonData = File.ReadAllText(path); 23 var ret = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonData); 24 return ret; 25 } 26 27 public void CreateData(string name) 28 { 29 var newData = new DataClass { Name = name }; 30 31 mutex.WaitOne(); 32 var currentData = GetDataPrivate<List<DataClass>>(""); 33 34 if (!currentData.Any((data) => data.Name.Equals(newData.Name))) 35 { 36 SaveData(""); 37 } 38 mutex.ReleaseMutex(); 39 } 40 41 public void SaveData(string path) 42 { 43 } 44 } 45}
###修正後ソースコードの問題点
- 動作自体は、求めていたものが実現できている。
- 今回のGetData関数のように、クラス内外から同じ動作をする機能を使いたいときに、クラス外から呼ぶための関数とクラス内から呼ぶための関数と二つ用意する必要がある。
- これが必要な手間であるのかどうかを知りたい(もっと簡単な方法が存在する?)
試したこと
- C# ファイル読み書き 排他制御で調べる。
- 1ファイルに対するロックをかける方法はあるものの、プロセス全体で読み書きを制限する手段は見つけられなかった。
- C# マルチプロセス ファイル読み書き 排他制御で調べる
- やはり対象が1ファイルのみの物しか見つけられなかった。(ファイル自体をロックする方法)
補足情報(FW/ツールのバージョンなど)
- .NET Framework 4.7.2
- Windows 10
- Visual Studio 2015
回答1件
あなたの回答
tips
プレビュー