Can I prevent a script from launching twice using

2019-08-10 05:58发布

I would like to prevent a script from launching twice by using a PID file. There are many ways to implement exclusivity, but since my script will always run on a Linux machine and I would like to be able to detect stale PID files automatically, I would like to use flock(2) to implement this.

I was told long ago by a colleague that the following pseudocode is the right way to do this (open(..., 'w') means "open in write mode with O_CREAT"):

fd = open(lockfile, 'w');
write(fd, pid);
close(fd);
fd = open(lockfile);
flock(fd)
file_pid = read(fd)
if file_pid != pid:
    exit(1)
// do things

I am curious why he suggested the above instead of:

fd = open(lockfile, 'w')
flock(fd)
// do things

Presumably he suggested this because he thought the "create file if it doesn't exist" functionality of open(2) with O_CREAT is not atomic, that is, two processes who call open(2) at exactly the same time might get handles to two different files because the file creation is not exclusive.

My question is, is the latter code always correct on a Linux system, or if not, when is it not correct?

1条回答
Viruses.
2楼-- · 2019-08-10 06:32

flock is not 100% reliable: http://en.wikipedia.org/wiki/File_locking#Problems

The 1st recipe is rather intrusive in the sense that a subsequent invocation of the process could blindly overwrite the pid data written by the previous invocation effectively preventing the 1st process from running. At high repeated invocation rates it's thus possible for none of the processes to run.

To ensure file creation exclusivity use O_CREAT | O_EXCL. You'd need to handle untimely process death leaving the file behind, tho.

I'd suggest 2 files:

  • a lock file opened with O_CREAT | O_EXCL, used just for protecting the actual PID file operations, should exist for just very short periods of time, easy to decide if stale based on creation time.
  • the actual PID file

Each process waits for the lock file to disappear (cleans it when it becomes stale), then attempts to create the lock file (only one instance succeeds, the others wait), checks the PID file existence/content (cleans up and deletes it if stale), creates a new PID file if it decides to run, then deletes the lock file and runs/exits as decided.

查看更多
登录 后发表回答