Linux多进程统计文件字母数:代码计数逻辑错误求助
修复多进程文件字母计数程序的逻辑错误
以下是你的代码中存在的核心问题及修复方案:
问题清单与修复说明
count_alphabet函数文件操作错误:函数未在内部打开目标文件,直接引用了main中已关闭的fd,子进程无法访问该文件描述符。需在函数内独立打开文件,操作完成后关闭。- 变量名笔误:
file_length未定义,实际应为file_size。 - 偏移范围计算错误:原逻辑导致每个子进程处理的字节数多1,需将
end_offset初始值改为start_offset + offset_range - 1,最后一个子进程再追加余数。 - 未定义变量引用:
snprintf中使用了未定义的temp,应改为child_buf。 isalpha的未定义行为:当char为有符号类型时,负数传入isalpha会触发未定义行为,需转换为unsigned char。- 管道描述符未正确关闭:子进程写完管道后需关闭写端,父进程需关闭写端以避免
read阻塞。 - 输出格式错误:最终输出文件名使用
%c,应改为%s。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <ctype.h> #include <sys/types.h> #include <sys/wait.h> #include <string.h> int count_alphabet(const char *filename, off_t start_offset, off_t end_offset) { int count = 0; char c; int fd = open(filename, O_RDONLY); if (fd < 0) { perror("Child failed to open file"); exit(1); } // 定位到起始偏移 if (lseek(fd, start_offset, SEEK_SET) == -1) { perror("Child lseek failed"); close(fd); exit(1); } // 计算需要读取的字节数,避免循环中重复判断偏移 off_t bytes_to_read = end_offset - start_offset + 1; for (off_t i = 0; i < bytes_to_read; ++i) { if (read(fd, &c, 1) == 1) { // 转换为unsigned char避免isalpha的未定义行为 if (isalpha((unsigned char)c)) { count++; } } else { // 读取出错或提前结束,直接退出 perror("Child read failed"); close(fd); exit(1); } } close(fd); return count; } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s <filename> <number_of_children>\n", argv[0]); exit(1); } const char *filename = argv[1]; int num_children = atoi(argv[2]); if (num_children <= 0) { fprintf(stderr, "Number of children must be a positive integer.\n"); exit(1); } int fd = open(filename, O_RDONLY); if (fd < 0) { perror("Failed to open file"); exit(1); } off_t file_size = lseek(fd, 0, SEEK_END); close(fd); if (file_size <= 0) { fprintf(stderr, "File is empty or unreadable.\n"); exit(1); } off_t offset_range = file_size / num_children; off_t extra_range = file_size % num_children; int pipefd[2]; if (pipe(pipefd) == -1) { perror("Pipe failed"); exit(1); } for (int i = 0; i < num_children; ++i) { pid_t pid = fork(); if (pid < 0) { perror("Fork failed"); exit(1); } else if (pid == 0) { // 子进程关闭不需要的读端 close(pipefd[0]); off_t start_offset = i * offset_range; off_t end_offset = start_offset + offset_range - 1; // 最后一个子进程加上余数 if (i == num_children - 1) { end_offset += extra_range; } int count = count_alphabet(filename, start_offset, end_offset); fprintf(stderr, "Process[%d] has found %d alphabet letters in (%ld ~ %ld).\n", getpid(), count, start_offset, end_offset); char child_buf[64]; // 不需要超大缓冲区,数字字符串足够小 int written_count = snprintf(child_buf, sizeof(child_buf), "%d\n", count); write(pipefd[1], child_buf, written_count); // 子进程写完关闭写端 close(pipefd[1]); exit(0); // 子进程完成任务后退出 } } // 父进程关闭不需要的写端 close(pipefd[1]); int total_count = 0; char parent_buf[1024]; int read_count; while ((read_count = read(pipefd[0], parent_buf, sizeof(parent_buf) - 1)) > 0) { parent_buf[read_count] = '\0'; char *line = strtok(parent_buf, "\n"); while (line != NULL) { total_count += atoi(line); line = strtok(NULL, "\n"); } } // 等待所有子进程结束 while (waitpid(-1, NULL, 0) > 0); fprintf(stderr, "Process[%d] has found %d alphabet letters in %s\n", getpid(), total_count, filename); close(pipefd[0]); return 0; }
内容的提问来源于stack exchange,提问作者kkk
相关产品推荐
相关产品推荐

