12.8. Locking a file
So far we did not consider the case when more than one programs are trying to read or to write a file. In real life, especially if you write CGI programs this can happen very often. Assume that you want to count the number of visitors. The CGI program fragment making the counting can be something like this:
1 Open "counter.txt" for input as 1 2 Line input #1,Counter 3 Close #1 4 Counter = Counter +1 5 Open "counter.txt" for output as 1 6 Print #1, Counter 7 Close #1
At first look there is no problem with this. But at second thought there is. There can be many CGI processes that run parallel. There is no guarantee that one program finishes its working before the next one starts. Processes are run parallel, and it means that the operating system runs a little piece of one process then runs another. Let's imagine the following unfortunate, but likely situation.
A CGI process runs the lines 1 to 3 and reads the counter value, let's say 100. Then the operating system hangs the running of this process for a while and runs another CGI process again the lines 1 to 3. This process also reads the counter value which was still not changed and is still 100. Then the first process gets focus again and it writes the incremented value 101. The second process, whenever it gets its time slice to run writes also the value 101 to the file. Both hits counted from 100 to 101 instead of one counting from 100 to 101 and the other from 101 to 102.
What is the solution?
The solution is to lock the file. A file can be locked when it is opened. We open the file for random access, lock it, read from it, increment, write the incremented value and close the file. No one else can intercept the file access because the file is locked. How does it look like in ScriptBasic?
1 Open "counter.txt" for random as 1 2 lock#1,write 2 Line input #1,Counter 3 Counter = Counter +1 4 rewind#1 5 Print #1, Counter 6 Close #1
The command lock does lock the opened file. (Obvious?) The first argument is the file number of the opened file. The second argument is the locking type. This type currently can be write, read and release. The meaning of the different types are:
- Write The file is locked for writing. Only the locking process can access the file until the lock is released.
- Read The file is locked for reading. Anyone can read the file but no one can write it until the lock is released.
- Release The file lock is released.
If the file is already locked by another process so that the actual locking cannot be performed the instruction lock waits until the other process releases the file.
The ScriptBasic instruction lock is an advisory lock. It means that it works only if all programs wanting to access the file use the lock statement before reading or writing the file. If a process locks a file and another process just goes on reading or writing the locking method may not work. The actual behavior is dependent on the operating system and as such you have to treat lock working more than advisory as non-guaranteed, or undefined behavior.
Actually the flock system call is used to implement the lock statement of ScriptBasic. This type of lock does not prohibit any process to read or write a locked file on UNIX. On Window NT operating system flock does not exist. The file locking functionality is implemented using the LockFileEx system call and locking the first 64Kbyte of the file. This results write and read failure in a process that tries to read or write the first 64Kbyte of the file and UNIX like behavior if it tries to access the file above the 64Kbyte.