Joe, many solutions have been proposed; I commented on some of them but I'd like to chime in with an overall view and some specifics and recommendations:
You have the following options:
- use filesystem locking: under Windows have both the reader and writer open (and create with the
CREATE_ALWAYS
disposition, respectively) the shared file in OF_SHARE_EXCLUSIVE
mode; have both the reader and writer ready to handle ERROR_SHARING_VIOLATION
and retry after some predefined period of time (e.g. 250ms)
- use file renaming to essentially transfer file ownership: have the writer create a writer-private file (e.g.
shared_file.tmpwrite
), write to it, close it, then make it publicly available to the reader by renaming it to an agreed-upon "public" name (e.g. simply shared-file
); have the reader periodically test for the existence of a file with the agreed-upon "public" name (e.g. shared-file
) and, when one is found, attempt to first rename it to a reader-private name (e.g. shared_file.tmpread
) before having the reader open it (under the reader-private name); under Windows use MOVEFILE_REPLACE_EXISTING
; the rename operation does not have to be atomic for this to work
- use other forms of interprocess communication (IPC): under Windows you can create a named mutex, and have both the reader and writer attempt to create (the existing mutex will be returned if it already exists) then acquire the named mutex before opening the shared file for reading or writing
- implement your own filesystem-backed locking: take advantage of
open(O_CREAT|O_EXCL)
or, under Windows, of the CREATE_NEW
disposition to atomically create an application lock file; unlike OF_SHARE_EXCLUSIVE
approach above, it would be up to you to deal with stale lock files (i.e. lock files left by a process which did not shut down gracefully such as after a crash.)
I would implement method 1.
Method 2 would also work, but it is in a sense reinventing the wheel.
Method 3 arguably has the advantage of allowing your reader process to wait on the writer process and vice-versa, eliminating the need for the arbitrary sleep delays between the retries of methods 1 and 2 (polling); however, if you are OK with polling then you should still use method 1
Method 4 is listed for completeness only, as it is complex to implement (when the lock file is detected to be stale, e.g. by checking whether the PID contained therein still exists, multiple processes can potentially be competing for its removal, which introduces a race condition requiring a second lock, which in turn can become stale etc. etc., e.g.:
- process A creates the lock file but dies without removing the lock file
- process A restarts and tries to acquire the lock file but realizes it is stale
- process B comes out of a sleep delay and also tries to acquire the lock file but realizes it is stale
- process A removes the lock file, which it knew to be stale, and recreates it essentially reacquiring the lock
- process B removes the lock file, which it (still) thinks is stale (although at this point it is no longer stale and owned by process A) -- violation