File read/write locks and mutex

There’s situations where you want to read or write a file and get an exception because the file cannot be accessed for some reason. The reason usually is another process/app/thread also accessing the file in the very same moment.

To circumvent this, I used mutex and that solved the issues at least for my usecase.

I raise this topic here, because I think this could be a nice addition to the corelib.


Please see the attached code and demo:
MutexDemo.7z (11.2 KB)

The demo is very simplified… you can try to read/write the test.txt file with another application while the patch is running and try to break it.

The code is not made for general use and should be adapted to be a proper node - but before that, let’s find out if this is a way to go or if there are still some edgecases or other pitfalls.


This is the gist:

public static Mutex s_Mutex = new Mutex(false, @"Global\MutexSettingsFile");

    /// <summary>
    /// Write to the Settings file
    /// </summary>
    /// <param name="content"></param>
    /// <param name="filepath"></param>
    /// <param name="timeout"></param>
    public static void Write(string content, string filepath, double timeout = 5)
    {
        try
        {
            s_Mutex.WaitOne(TimeSpan.FromSeconds(timeout));

            Utils.CreateFileIfNotExist(filepath);

            using (StreamWriter w = new StreamWriter(filepath, false, Encoding.UTF8))
            {
                w.Write(content);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("error writing to settings file:" + e.Message);
        }
        finally
        {
            s_Mutex.ReleaseMutex();
        }
    }
3 Likes

bumpybump

any opinions about this?

Before adding another way of reading and writing files, I wonder whether we should instead provide regions to do the locking / synchronization. Something like

  • Lock - in-process synchronization using a Monitor internally
  • Lock (Global) - inter-process synchronization using a Mutex internally

Yes, @Elias that is exactly the type of discussion i had in mind when starting this thread!

From a UI perspective i love the idea of having lock regions. I’m just not sure if they are the best tool here… What would be in the region? Just the File[IO], ByteReader and stuff like this or do you intend the user patches more like that in the region and if so, what?
I’m assuming here that one typically accesses files only once (lock needed) and then deals with its content in the patch (no lock needed).


despite that, i don’t know the Monitor thing… can you point me to some documentation?

A nice overview on those classes can be found at Overview of synchronization primitives | Microsoft Docs

Regarding your specific use case. Yes, I’d picture one FileReader in one Lock (Global) and one FileWriter in another Lock (Global) both locks using the same key. Well I guess in your example they would even be in different apps entirely.

Here’s a sketch
Lock.vl (38.0 KB)

1 Like

super elegant!

problem solved, i’d say… what about having it in the corelib?

btw: the Lock (without global) doesn’t seem to work.

And the reason seems to be, both regions have a different lock object. when feeding that from outside to both regions, it’s working.

image

As requested those regions have now been added to the CoreLib. Here is the relevant change log:

  • Using ensures the disposal of resources connected to its inputs after it executed. Essentially translates to the C# using statement.
  • Lock synchronizes access to a shared resource using an input key
  • Lock (Inter-process) synchronizes access to a shared resource across process boundaries
  • TempFile [IO] simply creates and provides a unique temp file

Preview build with those changes should be available soon. Also added above patch as help patch “HowTo Synchronize access to a file”.

3 Likes

Mega, thanks!

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.