这是令人尴尬的,显然我不(再次?)了解有关分叉的基本内容......
我期望下面的代码(在Linux,Centos 6.3下)打印
lock returned 0
unlock
lock returned 0
unlock
但事实并非如此,两个锁都会立即成功:
lock returned 0
lock returned 0
unlock
unlock
为什么?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
void main() {
int fd = open("lock.txt", O_WRONLY | O_CREAT);
int lock_ret;
fork();
lock_ret = flock(fd, LOCK_EX);
printf("lock returned %d\n", lock_ret);
fflush(stdout);
sleep(4);
printf("unlock\n");
fflush(stdout);
}
如果我删除fork()
并且只是手动启动两个进程,那么一切都按预期工作,一个锁成功,另一个阻塞并稍后成功。
答案 0 :(得分:2)
据男人们说:
flock()创建的锁与文件相关联,或者更多 确切地说,是一个打开文件表条目。这意味着重复文件 描述符(例如,由fork(2)或dup(2)创建)指的是 相同的锁,可以使用任何一个修改或释放此锁 这些描述符。此外,锁定由一个释放 对任何这些重复描述符进行显式LOCK_UN操作,或 当所有这些描述符都被关闭时。
因此,因为您在打开文件后分叉进程,所以它们共享同一个锁。这意味着另一个进程不能聚集在同一个文件上,直到child和parent关闭文件。
答案 1 :(得分:2)
如果您希望不在叉子中保留独占锁定,可以使用fcntl
。
struct flock fd_lock = { F_RDLCK, SEEK_SET, 0, 0, 0 };
fcntl(fd, F_SETLK, &fd_lock); // not across fork/exec
答案 2 :(得分:2)
flock()
手册中有一些狡猾的措辞:
flock()
创建的锁与打开的文件表条目相关联。这意味着重复的文件描述符(例如,由fork(2)
或dup(2)
创建)引用相同的锁,并且可以使用任何这些描述符修改或释放此锁。
您可以通过更全面地检测程序并明智地添加另一个fork来证明这一点。确保正确创建文件也是一个好主意 - 当您使用O_CREAT
时,open()
需要第三个参数来指定文件模式。
#include <fcntl.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
int main(void)
{
printf("%ld:%d: Before fork 1\n", (long)time(0), (int)getpid());
fork();
printf("%ld:%d: After fork 1\n", (long)time(0), (int)getpid());
int fd = open("lock.txt", O_WRONLY | O_CREAT, 0644);
int lock_ret;
fork();
printf("%ld:%d: After fork 2\n", (long)time(0), (int)getpid());
lock_ret = flock(fd, LOCK_EX);
printf("%ld:%d: lock returned %d\n", (long)time(0), (int)getpid(), lock_ret);
fflush(stdout);
sleep(4);
lock_ret = flock(fd, LOCK_UN);
printf("%ld:%d: unlock returned %d\n", (long)time(0), (int)getpid(), lock_ret);
fflush(stdout);
int corpse;
int status;
while ((corpse = wait(&status)) != -1)
printf("%ld:%d: PID %d died with status 0x%.4X\n", (long)time(0), (int)getpid(), corpse, status);
return 0;
}
示例运行:
1451543977:5731: Before fork 1
1451543977:5731: After fork 1
1451543977:5731: After fork 2
1451543977:5731: lock returned 0
1451543977:5732: After fork 1
1451543977:5733: After fork 2
1451543977:5733: lock returned 0
1451543977:5732: After fork 2
1451543977:5734: After fork 2
1451543981:5731: unlock returned 0
1451543981:5733: unlock returned 0
1451543981:5732: lock returned 0
1451543981:5731: PID 5733 died with status 0x0000
1451543985:5732: unlock returned 0
1451543985:5734: lock returned 0
1451543989:5734: unlock returned 0
1451543989:5732: PID 5734 died with status 0x0000
1451543989:5731: PID 5732 died with status 0x0000
请注意如何阻止不共享相同打开文件描述的进程;那些共享相同的打开文件描述的内容不会被阻止。
另请注意时间戳和(特别是)PID标记&#39;输出有助于使输出明确。
答案 3 :(得分:1)
来自Linux flock
手册页:
flock()创建的锁与打开的文件描述相关联(参见open(2))。这意味着重复文件描述符(例如,由 fork(2)或dup(2)创建)引用相同的锁,并且可以使用任何这些描述符修改或释放此锁。
您期待看到的行为。