Tuesday, January 9, 2007

Making shell scripts atomic

What do you do if you have a shell script that cannot be run twice at the same time, i.e. you have to wait until the script finishes before you can run it a second time.

The solution is to make the script check to see if it is running. If it is not running then let it start. The problem with this is it is possible to have the following scenario:

- start the script
- it checks to see if it is running
- start the script running a second time
- the second script checks to see if it is running
- flag that the first script is running and enter the critical section
- flag that the second script is running and enter the critical section

In other words, the check and the setting of the flag have to be atomic, i.e. you cannot have them be two steps in the script.

The solution is to use ln to create a link. The link will be the setting of the flag and the check. Then you can check the status of the ln command (the flag).

So here is the code to do it:
# Bourne Shell
#!/bin/sh

# create a filename for the ln
LOCK=`echo $0 | awk -F/ '{print $NF}' | awk -F. '{print $1}'`.LOCK

# create the link
ln $0 ${LOCK} 2> /dev/null

# see if we are already running
if [ $? -eq "0" ]; then
echo "running atomic script here"
echo "it just sleeps for 5 seconds"
sleep 5
/bin/rm ${LOCK}
else
echo "script is already running"
fi


Or if you perfer the C shell:
#C shell
#!/bin/csh

# create a filename for the ln
set LOCK=${0:r}.LOCK

# create the link
ln $0 ${LOCK} >& /dev/null

# see if we are already running
if ( ! $status ) then
echo "running atomic script here"
echo "it just sleeps for 5 seconds"
sleep 5
/bin/rm ${LOCK}
else
echo "script is already running"
endif

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.