private static FileReadWriteLock GetLock(this string filePath) { filePath = Path.GetFullPath(filePath ?? string.Empty); lock (locks) { if (!locks.TryGetValue(filePath, out var locker)) { locks.Add(filePath, locker = new FileReadWriteLock(filePath)); } return(locker); } }
private static int RunFileLocker(FileLockerOptions options) { var locker = new FileReadWriteLock(options.FilePath); var tasks = new List <Task>(); var exceptions = new ConcurrentBag <Exception>(); if (options.Access.HasFlag(FileAccess.Read)) { tasks.Add(Task.Run(() => { try { while (!string.IsNullOrEmpty(options.StartWaitForFile) && !options.StartWaitForFile.FileExists()) { Thread.Sleep(0); } var ends = DateTime.UtcNow.AddMilliseconds(options.RetryDurationMs); while (DateTime.UtcNow < ends) { using (locker.AcquireRead()) { if (options.Verbose) { Console.WriteLine("Data accessed to read"); } if (options.FilePath.FileExists()) { using (var reader = new StreamReader(new FileStream(options.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read))) { var text = reader.ReadLine(); if (options.Verbose) { Console.WriteLine("Data read : {0}", text); } } } } Thread.Sleep(0); } } catch (Exception e) { exceptions.Add(e); } })); } if (options.Access.HasFlag(FileAccess.Write)) { tasks.Add(Task.Run(() => { try { while (!string.IsNullOrEmpty(options.StartWaitForFile) && !options.StartWaitForFile.FileExists()) { Thread.Sleep(0); } var ends = DateTime.UtcNow.AddMilliseconds(options.RetryDurationMs); while (DateTime.UtcNow < ends) { using (locker.AcquireWrite()) { if (options.Verbose) { Console.WriteLine("Data accessed to write"); } using (var writer = new StreamWriter(new FileStream(options.FilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) writer.WriteLine("Hello my data"); if (options.Verbose) { Console.WriteLine("Data wrote"); } } Thread.Sleep(0); } } catch (Exception e) { exceptions.Add(e); } })); } tasks.ForEach(p => p.Wait()); if (exceptions.IsEmpty) { return(0); } else { var sb = new StringBuilder(); foreach (var exception in exceptions) { sb.AppendLine(Format(exception)); } File.WriteAllText($"{Guid.NewGuid():N}.errors.log", sb.ToString()); return(-1); } }
public void TestFileReadWriteLock() { const int iterations = 100; var fileName = $"{Guid.NewGuid():N}.dat"; var mre = new ManualResetEvent(false); var counters = new int[6]; var locked = counters.Select(p => FileAccess.ReadWrite).ToArray(); var threads = Enumerable.Range(0, counters.Length) .Select(p => Task.Run(() => { var locker = new FileReadWriteLock(fileName); mre.WaitOne(); if (p % 3 == 0) { // Writer for (var i = 0; i < iterations; i++) { using (locker.AcquireWrite()) { // Check only 1 writer and no readers at a time Assert.IsTrue(locked.All(l => l == FileAccess.ReadWrite), "Writer concurrency detected"); locked[p] = FileAccess.Write; counters[p] += 1; Thread.Sleep(5); locked[p] = FileAccess.ReadWrite; } } } else { // Reader for (var i = 0; i < iterations; i++) { using (locker.AcquireRead()) { // Check readers but no writer at a time Assert.IsTrue(locked.All(l => l == FileAccess.ReadWrite || l == FileAccess.Read), "Reader concurrency detected"); locked[p] = FileAccess.Read; counters[p] += 1; Thread.Sleep(0); locked[p] = FileAccess.ReadWrite; } } } })).ToList(); // Starts all threads mre.Set(); threads.ForEach(p => p.Wait()); foreach (var counter in counters) { Assert.AreEqual(iterations, counter); } }