这是我第一次使用 unix 命名管道进行测试。下面是一个简单的示例,它尝试每秒读取给定的管道,并在成功时将“触发”输出到标准输出。使用 bash 脚本,我可以将该值写入程序按预期读取的管道。
问题是,尽管只将值写入管道一次,但程序会在接下来的每个循环中继续读取该值。我能找到的每个教程都告诉我,从管道读取的所有内容基本上都被删除了,如果想要刷新管道,只需阅读所有内容即可。但是下面的程序在没有新输入的情况下一遍又一遍地输出值。
main.cpp
// std
#include <iostream>
// unix
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char* argv[]) {
// create named pipe
mkfifo("/tmp/alarm_motion", 0666);
for(;;){
int fifo = open("/tmp/alarm_motion", O_RDONLY | O_NONBLOCK);
char temp[sizeof(int)];
int st = read(fifo, temp, sizeof(temp));
if(st == 0){
int res = atoi(temp);
std::cout << "fifo" << res;
if(res == 1){
std::cout << " -> triggered";
close(fifo);
}
std::cout << std::endl;
}
sleep(1);
}
}
测试.sh
#!/bin/bash
pipe=/tmp/alarm_motion
echo 1 > $pipe
如果我编译程序,启动它,并在几个周期后执行脚本,我会收到下面的输出
示例输出
fifo0
fifo0
fifo0
fifo0
fifo0
fifo0
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
虽然我希望得到以下输出
期望的输出
fifo0
fifo0
fifo0
fifo0
fifo0
fifo0
fifo1 -> triggered
fifo0
fifo0
fifo0
fifo0
fifo0
有人能告诉我我做错了什么吗?
Raspbian 8 上的 g++(Raspbian 4.9.2-10)
最佳答案
你的程序有一些严重的缺陷:
文本形式的整数可能比
int
的大小多。例如,文本"12345678"
是 8 字节(不包括字符串终止符!),这应该与4
的通常大小进行比较sizeof(int)
。没有人说您读取的数据将以零结尾。这意味着所有将您读取的数据视为以零结尾的字符串(例如
atoi
)的函数都不会可靠地工作。当管道被另一端关闭时,
read
函数返回0
。这意味着您尝试使用的数据并不真正存在。read
调用(在返回0
之后)实际上并未读取任何内容。您有严重的资源泄漏,因为您一遍又一遍地
打开
管道而不关闭它。您处理任何事情都没有错误。
最后,您似乎一遍又一遍地读取相同的数据可能是因为编译器如何实现您的 temp
数组。它只是重复使用相同的内存。因为你只是继续一遍又一遍地循环,你会一遍又一遍地看到相同的数据,因为数组的位置是相同的,并且编译器(或你的程序)已经以任何方式清除了两者之间的内存。管道被冲洗,你的内存内容没有。
关于c++ - 读取命名管道不会刷新它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43465927/