Friday, June 13, 2014

System-Wide Mutex

It's been a long long time since I actually posted anything directly to do with Java programming, so here I am to make up for that.

In one of my projects I needed to create a system-wide mutex (a "mutex" being an object or "flag" to say that something is locked, e.g. a method or bit of code, so no other process can call it).  I needed it to be system-wide since I had multiple programs running on the same computer that needed to be in sync, so I couldn't use the synchronized keyword.

So I created a new class which I've called  FileSystemMutex.  It's very simple, and works by creating a temporary file to indicate that the lock is enabled and the file is deleted when the lock is released.  Because it uses the filesystem, it is "global" across everything that uses that filesystem.

Here is the code:-


import java.io.File;
import java.io.IOException;

public class FileSystemMutex {
   
    private File file;
    private long max_duration;
   
    public FileSystemMutex(String _filename, long _max_duration) {
        super();
       
        file = new File(_filename);
        max_duration = _max_duration;
    }
   
   
    public void waitForLock() throws IOException {
        while (isLocked()) {

            // This is my own function.
            // Surely everyone's written their own "Thread.sleep()" 
            // wrapper by now?
            Functions.delay(100); // Wait for a sec 
        }
        lock();   
    }
   
   
   
private boolean isLocked() {
        boolean exists = file.exists();
        if (exists) {

            // It might exist but is it too old?
            long age = file.lastModified();
            if (age + max_duration < System.currentTimeMillis()) {
                // Too old!
                release(); // Delete the file
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }
   
   
    private void lock() throws IOException {
        file.createNewFile();
    }
   
   
    public void release() {
        file.delete();
    }

}



One thing to always remember with locks it to ensure that under no circumstances should the lock get left on, usually by a program ending prematurely.  This is why I've included the failsafe "maximum duration" parameter, so if the process that created the lock "crashes", the lock will still be released, eventually.

You would use it like this:-

    private static FileSystemMutex fsmutex = 
        new FileSystemMutex("my_lock", 1000*60); // Might as well make it static

 
    public void MyFunction() {
        fsmutex.waitForLock();
        try {
            [ do something that requires locking this bit of the code]

        } finally {
            fsmutex.release();

        }
    }


'Tis all.

No comments: