2

I have a program that can be ran several times. The program uses a working directory where it saves/manipulates its runtime files and puts results. I want to make sure that if several copies of the program run simultaneously, they won't use the same folder. To do this I add a hidden file in the work directory when it's created, that means that the directory is being used, and delete it when the program exits. When a program wants to use a certain directory as its working directory, it'll check if that file exists, and if not it will use the directory, otherwise, it'll use a directory of the same name with its process id attached. The implementation is: (in Tcl)

upon starting:

if [file exists [db_work_area]/.folder_used] {
    reg set work_area_override [db_work_area]_[pid]
}
...
exec touch ${db_wa}/.folder_used

when exiting:

if [file exists [db_work_area]/.folder_used] {
    file delete [db_work_area]/.folder_used
}

This works when the copies of the program are opened one at a time, however I am afraid that if several copies of the program will be opened at the same time, there will be a problem with their synchronization. Meaning that two programs will check if the file exists, together, see that it doesn't both chose that directory, and only after that, they will add the file. How can I implement a semaphore that will be able to synchronize between the several different copies of the same program running?

SIMEL
  • 8,745
  • 28
  • 84
  • 130

1 Answers1

5

You should not do a [file exists] and later the touch, it works better to use open to do it in a single step with the EXCL permission.

Try to use something like this to create the file and fail if it already exists in an atomic way.

if {[catch {open ${db_wa}/.folder_used {WRONLY EXCL CREAT}} fd]} {
    # error happend, file exists
    # pick a different area
} else {
    # just close it again, like a touch to create the file
    close $fd
}
schlenk
  • 7,002
  • 1
  • 25
  • 29
  • I don't think that just because you can write something as one Tcl command, it means that it's atomic for the OS. There's a lot of C statements that reads the Tcl command, a lot that interprets it and a lot that executes it. And even a C statement isn't atomic. – potrzebie Nov 11 '12 at 15:27
  • 2
    @potrzebie, `[open]` in Tcl in the end calls the OS's `open(2)` or `CreateFile()` etc, so the atomicity is in fact guaranteed. – kostix Nov 11 '12 at 19:44
  • @kostix Is the Tcl source code guaranteed to do this in the future too? Where's that documented? – potrzebie Nov 12 '12 at 01:56
  • @potrzebie there is no guarantee that this will remain the same ever ever. But it's very likely to be. There is also no guarantee that the OS's 'open' command will be atomic, and there is no guarantee that a laws of physics will continue to behave the same tomorrow. It's just very likely. – Nir Levy Nov 12 '12 at 07:58
  • IIRC, POSIX makes some guarantees about the `open()` system call when the `O_EXCL` flag is passed in. (Which might even be properly respected by implementations when on a local filesystem…) Tcl's `open` with the `EXCL` flag ends up using the same API. – Donal Fellows Nov 12 '12 at 10:32