在 linux 中无法使用 fcntl 切换到阻止模式
cannot switch to blocking mode using fcntl in linux
我有一个示例程序:
int main()
{
const char* fn = "/tmp/tmpfifo";
int i = mkfifo(fn, 0666);
int fd = open(fn, O_RDONLY | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
char buf[1024];
int rd= read(fd, buf, 100);
cout << rd << endl;
remove(fn);
return 0;
}
似乎在从文件描述符中删除非阻塞标志后,read
调用应该阻塞,直到有内容写入 FIFO,但我的程序总是在没有阻塞的情况下运行并且 rd=0
结果。你能解释一下这种行为吗?谢谢!
奇怪!我尝试了一个代码,它在没有 O_NONBLOCK 的情况下打开文件,然后分 3 个阶段进行。尽管 O_NONBLOCK 标志结果重置,但第 3 阶段没有正确运行!
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char buf[1024];
int rd;
const char* fn = "prova.txt";
int i = mkfifo(fn, 0666);
int fd = open(fn, O_RDONLY); // | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
//flags &= ~O_NONBLOCK;
printf("1) Waits!\t\tflags=0%08o\n",flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
flags |= O_NONBLOCK;
printf("2) Doesn't wait!\tflags=0%08o\n",flags);
fcntl(fd, F_SETFL, flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
//This doen't act the flag ????
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
flags=fcntl(fd, F_GETFL);
printf("3) Waits!\t\tflags=0%08o\n",flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
puts("End!");
return 0;
}
这是命令序列和输出:
sergio@zarathustra:~$ ./a.out &
[2] 6555
sergio@zarathustra:~$ echo xxx >> prova.txt
1) Waits! flags=000100000
4 100000
2) Doesn't wait! flags=000104000
0 104000
3) Waits! flags=000100000
0 100000
End!
sergio@zarathustra:~$
我查看了您的代码,乍一看它应该可以工作。没有错误 returned,你似乎没有违反任何规则,但它只是没有阻塞。
所以我继续跟踪 read
调用以查看它在做什么:
它一直到 the pipe_read function,没有任何阻挡。一旦到达那里,它就会意识到管道的另一边没有人,returns EOF。
所以这显然是设计使然,但是只有管道 open
调用会在没有编写器的情况下尝试阻塞,一旦 open
returns 它只是假设有必须是该管道另一端的编写器,或者您是非阻塞的并准备好处理它。这有点道理。如果您尝试从管道 read
但写入器不在(或者一开始就不存在),您不想永远在那里等待。
如果您想等到编写器打开管道,请不要在 open
调用中使用 O_NONBLOCK
。如果您确实在 open
中使用 O_NONBLOCK
,那么管道的另一端可能没有任何人,并且 read
调用可能只是 return EOF 而不会阻塞。
所以简而言之,当你阅读它时,确保有人在管道的另一端。
您看到的行为是正常的。您已完成以下操作:
- 使用
O_NONBLOCK
打开 FIFO 的读取端,这样 FIFO 上就不需要写入程序了。这保证 open()
将立即成功。
- 在后续读取之前禁用
O_NONBLOCK
。您现在已经回到了与标准(阻塞)情况相同的位置,其中 FIFO 具有 reader 和写入器,但写入器关闭了 FIFO。那时,reader 应该看到文件结尾,这就是您所看到的。
我有一个示例程序:
int main()
{
const char* fn = "/tmp/tmpfifo";
int i = mkfifo(fn, 0666);
int fd = open(fn, O_RDONLY | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
char buf[1024];
int rd= read(fd, buf, 100);
cout << rd << endl;
remove(fn);
return 0;
}
似乎在从文件描述符中删除非阻塞标志后,read
调用应该阻塞,直到有内容写入 FIFO,但我的程序总是在没有阻塞的情况下运行并且 rd=0
结果。你能解释一下这种行为吗?谢谢!
奇怪!我尝试了一个代码,它在没有 O_NONBLOCK 的情况下打开文件,然后分 3 个阶段进行。尽管 O_NONBLOCK 标志结果重置,但第 3 阶段没有正确运行!
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char buf[1024];
int rd;
const char* fn = "prova.txt";
int i = mkfifo(fn, 0666);
int fd = open(fn, O_RDONLY); // | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
//flags &= ~O_NONBLOCK;
printf("1) Waits!\t\tflags=0%08o\n",flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
flags |= O_NONBLOCK;
printf("2) Doesn't wait!\tflags=0%08o\n",flags);
fcntl(fd, F_SETFL, flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
//This doen't act the flag ????
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
flags=fcntl(fd, F_GETFL);
printf("3) Waits!\t\tflags=0%08o\n",flags);
rd= read(fd, buf, 100);
printf("%d %o\n",rd,flags);
puts("End!");
return 0;
}
这是命令序列和输出:
sergio@zarathustra:~$ ./a.out &
[2] 6555
sergio@zarathustra:~$ echo xxx >> prova.txt
1) Waits! flags=000100000
4 100000
2) Doesn't wait! flags=000104000
0 104000
3) Waits! flags=000100000
0 100000
End!
sergio@zarathustra:~$
我查看了您的代码,乍一看它应该可以工作。没有错误 returned,你似乎没有违反任何规则,但它只是没有阻塞。
所以我继续跟踪 read
调用以查看它在做什么:
它一直到 the pipe_read function,没有任何阻挡。一旦到达那里,它就会意识到管道的另一边没有人,returns EOF。
所以这显然是设计使然,但是只有管道 open
调用会在没有编写器的情况下尝试阻塞,一旦 open
returns 它只是假设有必须是该管道另一端的编写器,或者您是非阻塞的并准备好处理它。这有点道理。如果您尝试从管道 read
但写入器不在(或者一开始就不存在),您不想永远在那里等待。
如果您想等到编写器打开管道,请不要在 open
调用中使用 O_NONBLOCK
。如果您确实在 open
中使用 O_NONBLOCK
,那么管道的另一端可能没有任何人,并且 read
调用可能只是 return EOF 而不会阻塞。
所以简而言之,当你阅读它时,确保有人在管道的另一端。
您看到的行为是正常的。您已完成以下操作:
- 使用
O_NONBLOCK
打开 FIFO 的读取端,这样 FIFO 上就不需要写入程序了。这保证open()
将立即成功。 - 在后续读取之前禁用
O_NONBLOCK
。您现在已经回到了与标准(阻塞)情况相同的位置,其中 FIFO 具有 reader 和写入器,但写入器关闭了 FIFO。那时,reader 应该看到文件结尾,这就是您所看到的。