[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::digital_unix

Title:DIGITAL UNIX(FORMERLY KNOWN AS DEC OSF/1)
Notice:Welcome to the Digital UNIX Conference
Moderator:SMURF::DENHAM
Created:Thu Mar 16 1995
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:10068
Total number of notes:35879

9908.0. "shell script locking" by GOBUCS::COOLEY (Megan and Michelle's Daddy) Wed May 21 1997 13:19

I want to set up a shell script which does this:

 - do some pre-processing
 - lock out other processes running this script or wait until free

 - do bit that can only be done one at a time

 - free lock
 - do some post-processing

Anyone have a shell script to do exclusive locking?
Lock should be freed if process dies.  Lock queue should be FIFO.

Thanks,
Warren
T.RTitleUserPersonal
Name
DateLines
9908.1Sample lock scriptSIOG::BR_MURPHYThu May 22 1997 10:5237
    Within a shellscript you could try 
    
    trap 'rm $LOCK_FILE' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    	:
    	:
    Do some processing
    	:
    	:
    while [ -f $LOCK_FILE ]	# Sleep while another process running
    do
    	LOCK_PID=LOCK_PID=`cat $LOCK_FILE`
    	if ps -eaf | grep $LOCK_PID | grep -v grep > /dev/null 2>&1
    	then
    		sleep 10	# Process still running
    	else
    		break		# Process no longer running
    	fi
    done
    
    echo $$ > $LOCK_FILE	# Lock out other processes
    
    	:
    	:
    Do bit that can only be done one at a time
    	:
    	:
    rm $LOCK_FILE
    
    
    Obviously, this is by no means infallible...if your unlucky in the
    timing you may get more than one process breaking out of the while loop
    & trying to do the processing at the same time, but I expect it's the
    best you'll get, unless you perform a secondary check that the PID of
    the running process matches that contained in the LOCK_FILE.
    
    Brendan
    
9908.2Reducing time lag between test-and-setIOSG::MARSHALLFri May 23 1997 13:2646
>> if you're unlucky 

Could you reduce the 'unluckiness' window by setting noclobber and looping round
again if the write to the lockfile failed?

In fact, I think you can simplify the locking code to (using ksh):

set -C
# pre-processing
...

# take out exclusive lock
(while ! echo $$ > LCKFILE; do    # Loop while we can't create the lockfile
    if ! ps -p $(<LCKFILE); then
        rm LCKFILE                # Remove file if owning process has died
    else
        sleep 1
done) 2> /dev/null                # Discard shell errors if can't write to file

# do bit that can only be done one at a time
...

# free lock
rm LCKFILE

# do some post-processing
...

Of course, as this uses a world-writeable lock file, it relies on everyone
cooperating and playing by the rules.  Also, this doesn't guarantee FIFO
operation if two or more processes are waiting on the lock; you'd need a more
sophisticated queueing system to do that.

For example, successive processes could append their PIDs to the file when they
wait on the lock.  Then, to release the lock the holding process just removes
its PID, rather than deleting the file.  This signals to the waiting processes
that the lock is free, but only the process next-in-line is allowed to take the
lock, bumping all the others one up the queue at the same time.

Finally, I don't know how 'atomic' the shell's test-and-set action around
redirection-with-noclobber is, so there's still probably a window of opportunity
for this to fail.  If this is really important, you might want to knock-up a
trivial C program to implement a guaranteed lock mechanism with creat(2) or
proper semaphores.

Scott
9908.3AddendumIOSG::MARSHALLFri May 23 1997 13:293
Oh, I forgot about the output from ps, so change the 'done' line to:

done) >/dev/null 2>&1             # Discard unwanted diagnostics