在 STDOUT_FILENO 上使用 fcntl F_SETLKW 合法吗?
Is using fcntl F_SETLKW on STDOUT_FILENO legal?
我有多个进程通过主程序的 fork 产生,这意味着它们输出到相同的标准输出(我想要的)。但是我需要以某种方式防止输出交错。我已经使用 fcntl 锁来同步对日志文件的访问,所以我也想将它用于 stdout。
然而 this 博客 post 声称 fcntl 锁是 associated with an [i-node, pid] pair
。 stdout 有 inode 吗?我决定试试看
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
void do_log(const char *msg) {
printf("%5ld: %s\n", getpid(), msg);
}
void try_lock(void) {
do_log("Trying to lock stdout...");
struct flock fl = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0,
};
if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
perror("fcntl - lock");
exit(1);
}
do_log("Stdout locked");
sleep(2);
do_log("Trying to unlock stdout...");
fl.l_type = F_UNLCK;
if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
perror("fcntl - unlock");
exit(1);
}
do_log("Stdout unlocked");
}
int main(void) {
if (fork()) {
try_lock();
} else {
try_lock();
}
wait(NULL);
return 0;
}
这似乎有效
17156: Trying to lock stdout...
17155: Trying to lock stdout...
17155: Stdout locked
17155: Trying to unlock stdout...
17155: Stdout unlocked
17156: Stdout locked
17156: Trying to unlock stdout...
17156: Stdout unlocked
但在 fcntl 的联机帮助页中我注意到 If fildes refers to a typed memory object, the result of the fcntl() function is unspecified.
但我不知道那是什么意思。
所以我想我有两个问题:
- 像这样在 stdout 上使用 fcntl lock 是否保证有效?
- 如果对 1. 的回答是肯定的,那么博客 post 关于
[i-node, pid]
的内容是错误的还是 stdout 实际上有一个 i 节点?
索引节点号(连同设备号)纯粹是文件的唯一标识符。在现代用法中,它与磁盘文件系统结构无关。所有文件(和文件描述符指的是打开文件的实例)都有一个 inode 编号,并且对它们至少执行 fcntl
"makes sense"。但是,根据 POSIX:
Record locking shall be supported for regular files, and may be supported for other files.
可能有些文件类型 Linux 不支持锁定;我不确定。
另请注意,锁定纯粹是建议 - 如果进行写入的进程在执行访问之前未尝试获取锁定,则它没有任何效果。
这可能更有意义,特别是如果您使用 fork
而没有 exec
,通过共享内存进行锁定。在分叉之前,mmap
一个 MAP_ANON|MAP_SHARED
区域并在其中设置一个进程共享互斥锁。如果任何进程可能会意外终止,您可以将其设为健壮的互斥锁。这保证有效,而且应该更快,因为它纯粹是一个用户空间操作,除了锁争用。
我有多个进程通过主程序的 fork 产生,这意味着它们输出到相同的标准输出(我想要的)。但是我需要以某种方式防止输出交错。我已经使用 fcntl 锁来同步对日志文件的访问,所以我也想将它用于 stdout。
然而 this 博客 post 声称 fcntl 锁是 associated with an [i-node, pid] pair
。 stdout 有 inode 吗?我决定试试看
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
void do_log(const char *msg) {
printf("%5ld: %s\n", getpid(), msg);
}
void try_lock(void) {
do_log("Trying to lock stdout...");
struct flock fl = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0,
};
if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
perror("fcntl - lock");
exit(1);
}
do_log("Stdout locked");
sleep(2);
do_log("Trying to unlock stdout...");
fl.l_type = F_UNLCK;
if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
perror("fcntl - unlock");
exit(1);
}
do_log("Stdout unlocked");
}
int main(void) {
if (fork()) {
try_lock();
} else {
try_lock();
}
wait(NULL);
return 0;
}
这似乎有效
17156: Trying to lock stdout...
17155: Trying to lock stdout...
17155: Stdout locked
17155: Trying to unlock stdout...
17155: Stdout unlocked
17156: Stdout locked
17156: Trying to unlock stdout...
17156: Stdout unlocked
但在 fcntl 的联机帮助页中我注意到 If fildes refers to a typed memory object, the result of the fcntl() function is unspecified.
但我不知道那是什么意思。
所以我想我有两个问题:
- 像这样在 stdout 上使用 fcntl lock 是否保证有效?
- 如果对 1. 的回答是肯定的,那么博客 post 关于
[i-node, pid]
的内容是错误的还是 stdout 实际上有一个 i 节点?
索引节点号(连同设备号)纯粹是文件的唯一标识符。在现代用法中,它与磁盘文件系统结构无关。所有文件(和文件描述符指的是打开文件的实例)都有一个 inode 编号,并且对它们至少执行 fcntl
"makes sense"。但是,根据 POSIX:
Record locking shall be supported for regular files, and may be supported for other files.
可能有些文件类型 Linux 不支持锁定;我不确定。
另请注意,锁定纯粹是建议 - 如果进行写入的进程在执行访问之前未尝试获取锁定,则它没有任何效果。
这可能更有意义,特别是如果您使用 fork
而没有 exec
,通过共享内存进行锁定。在分叉之前,mmap
一个 MAP_ANON|MAP_SHARED
区域并在其中设置一个进程共享互斥锁。如果任何进程可能会意外终止,您可以将其设为健壮的互斥锁。这保证有效,而且应该更快,因为它纯粹是一个用户空间操作,除了锁争用。