【发布时间】:2015-01-13 04:28:10
【问题描述】:
基于answer,我正在模拟有两个作家和一个读者。
所以,我创建了两个管道,并为每个管道写入了一个实际字符串,一个字符串通知读者他已经完成了这个编写器。
但是,它只会读取第一个字符串,有时会读取第二个管道的结束字符串。
我错过了什么?
reader.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
struct pollfd fdtab[w_no];
int done[w_no];
/* create the FIFO (named pipe) */
int i;
for (i = 0; i < w_no; ++i) {
//fd[i] = open(myfifo[i], O_RDONLY);
while( (fd[i] = open(myfifo[i], O_RDONLY)) == -1);
fdtab[i].fd = fd[i];
fdtab[i].events = POLLIN;
fdtab[i].revents = 0;
done[i] = 0;
}
char buffer[1024];
ssize_t bytes;
printf("Edw prin\n");
while(not_all_done(done, w_no)) {
int retpoll = poll(fdtab, w_no, 300);
if(retpoll != 0) {
if (retpoll == -1) {
perror("poll");
break;
}
for(i = 0; i < w_no; ++i) {
if(fdtab[i].revents & POLLIN) {
printf("Edw %d %d %d %d\n", i, retpoll, fdtab[i].revents, POLLIN);
//read the written pipe
while((bytes = read(fdtab[i].fd, buffer, sizeof(buffer))) > 0)
printf("Read |%s| %d %d %d\n", buffer, retpoll, fdtab[i].revents, POLLIN);
if(!strcmp(buffer, "++"))
done[i] = 1;
}
}
} else if (retpoll == 0) {
/* the poll has timed out, nothing can be read or written */
printf("timeout from writer\n");
break;
}
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
}
free_names(myfifo, w_no);
return 0;
}
writer.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
/* create the FIFO (named pipe) */
int i;
int bytes;
for (i = 0; i < w_no; ++i) {
mkfifo(myfifo[i], 0666);
fd[i] = open(myfifo[i], O_WRONLY);
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);
printf("wrote %d bytes, %d\n", bytes, sizeof("Hi+"));
while( (bytes = write(fd[i], "++", sizeof("++"))) == 2);
printf("wrote %d bytes, %d\n", bytes, sizeof("++"));
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
unlink(myfifo[i]);
}
free_names(myfifo, w_no);
return 0;
}
示例输出:
/tmp/myfifo_0
/tmp/myfifo_0
/tmp/myfifo_1
/tmp/myfifo_1
wrote 4 bytes, 4
wrote 3 bytes, 3
wrote 4 bytes, 4
Edw prin
wrote 3 bytes, 3
Edw 0 2 17 1
Read |Hi+| 2 17 1
Edw 1 2 1 1
Read |Hi+| 2 1 1
^C
编辑
当Hi+ 字符串到达时,bytes 的值为 7。
我试图发送的结束字符串是++,但它没有被读取。
EDIT_2
char* concat(char *s1, char *s2) {
char *result = malloc(strlen(s1) + strlen(s2) + 1); //+1 for the null-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
void fill_names(char* f[], int n) {
int i = 0;
char * buf = "/tmp/myfifo_";
char str[15];
for (; i < n; ++i) {
sprintf(str, "%d", i);
f[i] = concat(buf, str);
}
}
想法
也许作者在从管道中读取数据之前关闭并取消链接?如果是这样,我应该怎么做才能防止这种情况发生?
如果在此之前放一个sleep(10),它不会改变行为,它只会读取前两个字符串,但需要更多时间然后它会挂断(因为它等待结束字符串)。
EDIT_3
我还有一个 main.c,它执行读取器和写入器。
【问题讨论】:
-
您能说明
fill_names()的定义吗?我的印象是您使用静态来构建名称。 -
当然是@Christophe,感谢您抽出宝贵时间。
-
concat 是否使用静态缓冲区?还是返回一个 strdup() ?我之所以问,是因为您在日志开头显示了每个管道的名称的两倍,就好像您会使用相同的管道一样。
-
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);表示只要只写3个字节就会循环再写一次,不是吗? -
天哪,我怎么错过了?好的@Christophe,在你的回答中你可以解释我需要改变什么。
标签: c ipc named-pipes system-calls polling