A simple demo to start with:
1. Process 1: lock a region, write a record, pause
2. Process 2: attempt to lock the same region
3. Allow Process 1 to release the lock
4. Process 2 continues
Converting the code was easy (I thought), but no matter what I did I always found the region was locked for the second process - the lock was not being released.
I blame the documentation, and possibly the implementation.
What is not obvious is that the current file position must be reset to the original locking position before the lock gets released. The write (of course) advances the current file position, so by the time we do the unlock we are unlocking a region for which we don't have the lock in the first place! Wouldn't it be better if msvcrt.locking returned a lock object, saving the file position? Anyway, here is my completed demo:
"""
lock_w.py
Run two copies, each in its own terminal session.
Allow one to write a number of records, then switch
to the other showing that it blocks on the same record.
Switch back and release the lock, and show that the
blocked process proceeds.
Also run with lock_r to demonstrate interaction with
read locks.
Default filename is rlock.dat
Clive Darke QA
"""
import msvcrt
import os
import sys
import time
from datetime import datetime
REC_LIM = 20
if len(sys.argv) < 2:
pFilename = "rlock.dat"
else:
pFilename = sys.argv[1]
fh = open(pFilename, "w")
# Do only once
Record = dict()
Record['Pid'] = os.getpid()
for i in range(REC_LIM):
Record['Text'] = "Record number %02d" % i
Record['Time'] = datetime.now().strftime("%H:%M:%S")
# Get the size of the area to be locked
line = str(Record) + "\n"
# Get the current start position
start_pos = fh.tell()
print "Getting lock for",Record['Text']
msvcrt.locking(fh.fileno(), msvcrt.LK_RLCK, len(line)+1)
fh.write(line) # This advances the current position
raw_input("Written record %02d, clear the lock?" % i)
# Save the end position
end_pos = fh.tell()
# Reset the current position before releasing the lock
fh.seek(start_pos)
msvcrt.locking(fh.fileno(), msvcrt.LK_UNLCK, len(line)+1)
# Go back to the end of the written record
fh.seek(end_pos)
fh.close()