Search code examples
bashlockingpid

locking a PID file


I have a function in a bash script that runs indefinitely in background and that shall be terminated by running again the same script. It is a sort of switch, when I invoke this script it starts or kills the function if already running. To do this I use a PID file:

#!/bin/bash

background_function() {
    ...
}

if [[ ! -s myscript.pid ]]
then
    background_function &
    echo $! > myscript.pid
else
    kill $(cat myscript.pid) && rm myscript.pid
fi

Now, I would like to avoid multiple instances running and race conditions. I tried to use flock and I rewrote the above code in this way:

#!/bin/bash

background_function() {
    ...
}

exec 200>myscript.pid
if flock -n 200
then
    background_function &
    echo $! > myscript.pid
else
    kill $(cat myscript.pid) && rm myscript.pid
fi

In doing so, however, I have a lock on the pid file but every time I launch the script again the pid file is rewritten by exec 200>myscript.pid and therefore I am unable to retrieve the PID of the already running instance and kill it.

What can I do? Should I use two different files, a pid file and a lock file? Or would it be better to implement other lock mechanisms by using mkdir and touch? Thanks.


Solution

  • If an echo $$ is atomic enough for you, you could use:

    echo $$ >> lock.pid
    lockedby=`head -1 lock.pid`
    if [ $$ != $lockedby ] ; then
        kill -9 $lockedby
        echo $$ > lock.pid
        echo "Murdered $lockedby because it had the lock"
    fi
    
    # do things in the script
    
    rm lock.pid