fcntl F_GETLK 总是返回真
Posted
技术标签:
【中文标题】fcntl F_GETLK 总是返回真【英文标题】:fcntl F_GETLK always return true 【发布时间】:2015-05-16 12:46:23 【问题描述】:我正在尝试使用锁定文件创建单个实例守护程序,但 fcntl()
似乎没有按预期工作...
int creat_lock_file (char * pid_fn)
struct flock pid_lck = F_WRLCK, SEEK_SET, 0, 0, 0 ;
/* Open/Create pid file */
int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
if (pid_fd == -1)
syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno));
return -1;
/* Place write lock on pid file */
if (fcntl(pid_fd, F_SETLK, &pid_lck) == -1)
/* Unhandled error ocured */
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close (pid_fd);
return -1;
/* Write PID to lock file */
char pid_lock_buf[11];
sprintf (pid_lock_buf, "%ld\n", (long) getpid ());
write (pid_fd, pid_lock_buf, strlen (pid_lock_buf)+1);
return 0;
int get_lock_file_status (char * pid_fn)
struct flock pid_lck = F_WRLCK, SEEK_SET, 0, 0, 0 ;
/* Open/Create pid file */
int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
if (pid_fd == -1)
syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno));
return -1;
/* try locking pid file*/
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1)
if(errno == EAGAIN || errno == EACCES) /* file already locked, close fd and return -1 */
close (pid_fd);
return -1;
else /* Unhandled error ocured */
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close (pid_fd);
return -1;
close (pid_fd);
return 0;
所以我调用get_lock_file_status
并在它返回-1 时退出以确保没有其他实例正在运行,而不是我做一些事情(fork chdir 等)并调用creat_lock_file
在成功创建一个 pid 文件后创建并锁定一个 pid 文件守护进程...
当编译和运行程序按预期运行时,运行会创建锁定文件并将 pid 写入其中,但是当第二个实例启动时,第二个实例只是打开同一个锁定文件并将它自己的 pid 写入其中!
我做错了什么? get_lock_file_status
中的第二个实例不应该返回 -1 吗?
【问题讨论】:
这似乎是错误的方法。对于编程文件锁,flock() 函数似乎是正确的方法,这个函数,在 linux 上,在 'man 2 flock' 或在:linux.die.net/man/2/flock> 中有详细说明 @user3629249:fcntl(2)
和 F_SET/GET/LK
很好,还有 POSIX,flock(2)
不是(尽管它被广泛使用)。这两种方法有不同的行为w.r.t。锁定继承和其他一些东西。 fcntl()
可以在文件区域上设置锁,flock()
不能。
【参考方案1】:
您以错误的方式检查F_GETLK
的结果。 fcntl(2)
和 F_GETLK
仅在错误时返回 -1。检查是否可以获得锁的正确方法是检查struct flock
的l_type
字段是否设置为F_UNLCK
,如下所示:
/* try locking pid file*/
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1)
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close(pid_fd);
return -1;
close(pid_fd);
return (pid_lck.l_type == F_UNLCK) ? 0 : -1;
应该可以将 creat_lock_file()
和 get_lock_file_status()
滚动到一个函数中,该函数打开文件(如果文件不存在则创建它),尝试对其设置锁定,并返回锁定是否成功(例如,文件描述符或-1
)。
顺便说一句,在将 PID 写入其中之前,您应该将 PID 文件truncate(2)
清零字节。假设您的进程的 PID 为 5,PID 文件中的旧 PID 为 123。写入“5”将使 PID 文件的内容为“523”。将文件截断为零字节可以解决这个问题。 (O_TRUNC
不起作用,因为您在打开文件以测试是否设置了锁定时会清除文件。)
在程序退出时使用unlink(2)
删除 PID 文件也很常见。这样,文件的不存在表明守护程序没有运行(尽管它不是万无一失的,因为进程或系统可能会崩溃)。
【讨论】:
您好,感谢您的回答,当我阅读您的回答时,我想到了您所说的测试文件是否存在不是一个好主意,因为程序可能很粗鲁,没有时间unlink()
文件,但是如果我读取文件并尝试查找 pid 以查看是否有任何进程以相同的 pid 运行?这是个好主意吗?
@AristosMiliaressis:即使守护进程崩溃并且不删除 PID 文件,使用文件锁定检查守护进程是否正在运行也将起作用。如果守护进程崩溃,那么文件锁会自动移除(因为它与进程绑定),并且新的守护进程实例将能够锁定文件(告诉它没有其他实例在运行)。
用于检查守护进程是否真的在运行,例如shell,检查是否存在与文件中具有相同PID的进程应该可以工作,是的。如果守护进程崩溃并且某些其他进程碰巧获得相同的 PID,它可能失败,但这并不常见。 (您也可以使用ps(1)
检查启动该过程的命令是什么来确定。)
我自己从未在 shell 中完成文件锁定,但这也应该是可能的(例如,如果您希望 shell 脚本执行与您的代码相同的操作)。例如,请参阅此答案:***.com/questions/1715137/…。
@AristosMiliaressis:你找到什么了吗?我稍微编辑了答案。明天我会检查并确保代码在我的机器上运行(尽管它应该通过查看它,前提是您在调用creat_lock_file()
后不要再次调用get_lock_file_status()
)。以上是关于fcntl F_GETLK 总是返回真的主要内容,如果未能解决你的问题,请参考以下文章