【发布时间】:2020-04-13 17:26:03
【问题描述】:
好吧,简短的故事是: 我有一个程序需要做 X,它做 0.25X。我使用 2 个叉子和 4 个管道,我不知道如何调试它。 (在 linux 环境中使用 eclipse c/c++)。
长篇大论: 我有一个程序需要从包含整数对的文本文件中计算 gcd(最大公约数)。这个程序有一个父亲(主要)和两个孩子(叉子),需要通过管道与父亲交谈。 (每个孩子 2 个管道。) 当我在 ubuntu 中编译并运行程序时,我没有收到任何错误,但程序没有完成它的任务。我不知道它在哪里/为什么会坏。我该如何调试呢?我在 eclipse c/c++ 中编码,调试器无法处理分叉。当我调试时,它正在从文件中读取所有数字(不计算 gcd),但是当我在 ubuntu 终端中运行时,它只读取第一行并中断。这是完整的代码:
int main(int argc, char **argv) {
if (argc != 2 || strcmp(argv[1], "--help") == 0) {
fprintf(stderr, "usage: %s <FILE NAME>\n", argv[0]);
return EXIT_FAILURE;
}
int pfd_child1_r[2], pfd_child1_w[2], pfd_child2_r[2], pfd_child2_w[2];
if (pipe(pfd_child1_r) == -1 || pipe(pfd_child1_w) == -1
|| pipe(pfd_child2_r) == -1 || pipe(pfd_child2_w) == -1) {
perror("cannot pipe()");
return EXIT_FAILURE;
}
createChilds(pfd_child1_r, pfd_child1_w, pfd_child2_r, pfd_child2_w);
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
perror("fopen(): ");
return EXIT_FAILURE;
}
char line[100];
char *token;
int numbers[2], num, line_count = 1, counter = 0, result = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
token = strtok(line, " ");
while (token != NULL) {
num = atoi(token);
if (num < 1 || counter == 2) {
fprintf(stderr, "illegal input at line %d\n",
line_count);
return EXIT_FAILURE;
}
numbers[counter] = num;
counter++;
token = strtok(NULL, " ");
}
counter = 0;
if (line_count % 2 == 0) { // use first child
write(pfd_child1_w[1], &numbers[0], sizeof(int));
write(pfd_child1_w[1], &numbers[1], sizeof(int));
} else { // use second child
write(pfd_child2_w[1], &numbers[0], sizeof(int));
write(pfd_child2_w[1], &numbers[1], sizeof(int));
}
if (line_count > 1) { // after first run alternate to get result
if (line_count % 2 == 0) { // read from second child
read(pfd_child2_r[0], &result, sizeof(int));
printf("%d %d\t\tgcd: %d\n", numbers[0], numbers[1], result);
} else { // read from first child
read(pfd_child1_r[0], &result, sizeof(int));
printf("%d %d\t\tgcd: %d\n", numbers[0], numbers[1], result);
}
}
line_count++;
}
fclose(fp);
return EXIT_SUCCESS;
}
void createChilds(int pfd_child1_r[2], int pfd_child1_w[2], int pfd_child2_r[2],
int pfd_child2_w[2]) {
switch (fork()) {
case -1:
perror("cannot fork()");
exit(EXIT_FAILURE);
case 0: /* First child: */
if (close(pfd_child1_r[0]) == -1) { /* Read end is unused */
perror("cannot close()");
exit(EXIT_FAILURE);
}
if (close(pfd_child1_w[1]) == -1) { /* Write end is unused */
perror("cannot close()");
exit(EXIT_FAILURE);
}
/* Duplicate stdout on write end of pipe; close duplicated descriptor */
if (pfd_child1_w[1] != STDOUT_FILENO) { /* Defensive check */
if (dup2(pfd_child1_r[1], STDOUT_FILENO) == -1) {
perror("cannot dup2()");
exit(EXIT_FAILURE);
}
if (close(pfd_child1_r[1]) == -1) {
perror("cannot close()");
exit(EXIT_FAILURE);
}
}
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd_child1_w[1] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd_child1_w[0], STDIN_FILENO) == -1) {
perror("cannot dup2()");
exit(EXIT_FAILURE);
}
if (close(pfd_child1_w[0]) == -1) {
perror("cannot close()");
exit(EXIT_FAILURE);
}
}
execlp("./v1_child", "./v1_child", NULL); /* Writes to pipe */
exit(EXIT_SUCCESS);
default: /* Parent go to next child */
break;
}
switch (fork()) {
case -1:
perror("cannot fork()");
exit(EXIT_FAILURE);
case 0: /* Second child: exec 'wc' to read from pipe */
if (close(pfd_child2_r[0]) == -1) { /* Read end is unused */
perror("cannot close()");
exit(EXIT_FAILURE);
}
if (close(pfd_child2_w[1]) == -1) { /* Write end is unused */
perror("cannot close()");
exit(EXIT_FAILURE);
}
/* Duplicate stdout on write end of pipe; close duplicated descriptor */
if (pfd_child2_w[1] != STDOUT_FILENO) { /* Defensive check */
if (dup2(pfd_child2_r[1], STDOUT_FILENO) == -1) {
perror("cannot dup2()");
exit(EXIT_FAILURE);
}
if (close(pfd_child2_r[1]) == -1) {
perror("cannot close()");
exit(EXIT_FAILURE);
}
}
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd_child2_w[1] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd_child2_w[0], STDIN_FILENO) == -1) {
perror("cannot dup2()");
exit(EXIT_FAILURE);
}
if (close(pfd_child2_w[0]) == -1) {
perror("cannot close()");
exit(EXIT_FAILURE);
}
}
execlp("./v1_child", "./v1_child", NULL); /* Writes to pipe */
exit(EXIT_SUCCESS);
default: /* Parent falls through */
break;
}
/* Parent closes unused file descriptors for pipe */
if (close(pfd_child1_r[1]) == -1 || close(pfd_child1_w[0]) == -1
|| close(pfd_child2_r[1]) == -1 || close(pfd_child2_w[0]) == -1) {
perror("cannot close()");
exit(EXIT_FAILURE);
}
第二个文件是 gcd 文件,我还没有完成它,应该继续获取数字的循环不存在。但我只想让第一行正常工作,然后我会修复其余的。
int gcd(int n1, int n2) {
if (n2 == 0)
return n1;
return gcd(n2, n1 % n2);
}
int main(int argc, char **argv) {
int n1, n2, result;
if (scanf("%d %d", &n1,&n2) != 2) {
fprintf(stderr, "error reading numbers in child\n");
return -1;
}
if (n1 > n2)
result = gcd(n1, n2);
else
result = gcd(n2,n1);
printf("%d", result);
}
【问题讨论】:
-
如果用户请求
--help,这不是错误,不应将使用消息写入stderr。 (cmd --help | less的频率是多少?)。 -
防御检查正在检查错误的描述符。不过,只要标准输入和标准输出都存在,它们就不会造成伤害。