Reputation: 4432
I'm working with two independent c/c++ applications on Windows where one of them constantly updates an image on disk (from a webcam) and the other reads that image for processing. This works fine and dandy 99.99% of the time, but every once in a while the reader app is in the middle of reading the image when the writer deletes it to refresh it with a new one.
The obvious solution to me seems to be to have the reader put some sort of a lock on the file so that the writer can see that it can't delete it and thus spin-lock on it until it can delete and update. Is there anyway to do this? Or is there another simple design pattern I can use to get the same sort of constant image refreshing between two programs?
Thanks,
-Robert
Upvotes: 3
Views: 2513
Reputation: 66661
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:
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)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 workopen(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.:
Upvotes: 2
Reputation: 40140
couldn't you store a few images? ('n' sounds like a good number :-)
Not too many to fill your disk, but surely 3 would be enough? if not, you are writing faster than you can process and have a fundamental problem anyhoo (tune to discover 'n').
Cyclically overwrite.
Upvotes: 0
Reputation: 620
Try using a synchronization object, probably a mutex will do. Whenever a process wants to read or write to a file it should first acquire the mutex lock.
Upvotes: 4
Reputation: 1703
Instead of deleting images, what about appending them to the end of the file? This would allow you to keep adding to the file while the reader is still operating without destroying the file. The reader can then delete the image when it's done with it (provided it is necessary) and move onto the next image. Or, the other option would be store the image in a buffer, for writing, and you test the file pointer. If it's set to the head of the file then you can go ahead and write from the buffer to the file. Otherwise, wait until reader finishes and puts the pointer back at the head of the file.
Upvotes: 0
Reputation: 31394
If you are willing to go with the Windows API, opening the file with CreateFile and passing in 0 for the dwShareMode will not allow any other application to open the file.
From the documentation:
Prevents other processes from opening a file or device if they request delete, read, or write access.
Then you'd have to use ReadFile, WriteFile, CloseFile, etc rather than the C standard library functions.
Upvotes: 3
Reputation: 40140
Or, as a really simple kludge, the reader creates a temp file (says, .lock
) before starting reading and deletes it afterwards. The write doesn't manipulate the file so long as .lock
exists.
That's how Open Office does it (and others) and it's probably the simplest to implement, no matter which platform.
Upvotes: 2
Reputation: 83577
Yes, a locking mechanism would help. There are, unfortunately, several to choose from. Linux/Unix e.g. has flock (2), Windows has a similar (but different) mechanism.
Another (somewhat hacky) solution is to just write the file under a temporary name, then rename it. Many filesystems guarantee that a rename is atomic, so this may work. This however depends on the fs, so it's a bit hacky.
Upvotes: 3