我有两个进程:和一个"阅读器">
写入器使用fallocate(2)
首先创建一个固定长度的文件(全是0),然后写入器向该文件写入数据。
我想让reader进程读取文件直到"边缘"。(写入器最后写入数据的文件偏移量),然后等待写入器添加更多数据。
这里有一些简单的程序示例,供作者和读者使用。注意,阅读器读取的速度会稍微快一点,所以在某些时候会碰到文件的边缘。当它遇到这种情况时,它应该查找一个数据元素并再次尝试,直到它读取到一个非零数据元素。
它不工作。似乎读者只能寻找并成功阅读一次。之后,它总是从当前文件位置读取0。(见下面的日志)
但是…如果我使用另一个终端窗口将文件复制到其他地方,则所有预期的数据都存在。所以看起来数据正在写入,但它不是可靠地读取。
有什么建议吗?
EDIT/SOLUTION
John Bollinger的建议解决了这个问题:
在fopen
之后和开始阅读之前添加这行:
setvbuf(fp, NULL, _IONBF, 0);
作家过程
/*
g++ fWriter.cpp -o fWriter -g -pg
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
printf("WRITER LAUNCHEDn");
const int N = 100;
FILE *fp = fopen("/tmp/someFile", "w");
if (!fp)
{
perror("fopen");
exit(1);
}
int itemLen = sizeof(uint32_t);
off_t len = itemLen * N;
int fd = fileno(fp);
if (fallocate(fd, 0, 0, len) == -1)
{
fprintf(stderr, "fallocate failed: %sn", strerror(errno));
exit(1);
}
for (uint32_t i = 1; i <= N; i++)
{
int numBytes = fwrite((void*)&i, 1, itemLen, fp);
if (numBytes == itemLen)
printf("[%u] Wrote %un", i, i);
else
printf("Write errorn");
fflush(fp);
sleep(1);
}
fclose(fp);
printf("WRITER COMPLETEn");
}
读者过程
/*
g++ fReader.cpp -o fReader -g -pg
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
printf("READER LAUNCHEDn");
FILE *fp = fopen("/tmp/someFile", "r");
if (!fp)
{
perror("fopen");
exit(1);
}
// New!
setvbuf(fp, NULL, _IONBF, 0);
int i = 1;
int itemLen = sizeof(uint32_t);
while (!feof(fp))
{
uint32_t val;
int numBytes = fread((void*)&val, 1, itemLen, fp);
if (numBytes != itemLen)
{
printf("Short readn");
continue;
}
printf("[%d] Read %un", i, val);
// wait for data
if (val == 0)
{
off_t curPos = ftello(fp);
off_t newPos = curPos - itemLen;
printf("Seek and try again. newPos %dn", newPos);
fseeko(fp, newPos, SEEK_SET);
}
i++;
//usleep(1100000);
usleep(900000);
}
fclose(fp);
}
读者日志
READER LAUNCHED
[1] Read 1
[2] Read 2
[3] Read 3
[4] Read 4
[5] Read 5
[6] Read 6
[7] Read 0
Seek and try again. newPos 24
[8] Read 7
[9] Read 8
[10] Read 9
[11] Read 10
[12] Read 11
[13] Read 0
Seek and try again. newPos 44
[14] Read 0
Seek and try again. newPos 44
[15] Read 0
Seek and try again. newPos 44
[16] Read 0
Seek and try again. newPos 44
[17] Read 0
Seek and try again. newPos 44
[18] Read 0
Seek and try again. newPos 44
[19] Read 0
Seek and try again. newPos 44
[20] Read 0
Seek and try again. newPos 44
[21] Read 0
Seek and try again. newPos 44
[22] Read 0
Seek and try again. newPos 44
流(由stdio.h FILE
对象表示的任何东西)可以完全缓冲,行缓冲或不缓冲。默认情况下,连接到常规文件的流将被完全缓冲。这当然就是为什么你的读者在当前文件位置读了一堆零之后,没有注意到作者已经覆盖了其中的一些。读取器将不再从底层文件中查询已经缓冲的文件区域的数据。
在这种情况下,读者可以而且应该使用setvbuf()
将文件的缓冲模式改为无缓冲。