使用mmap实现父子进程文件处理时的进程通信与数据损坏问题
问题描述
我编写了一个基于mmap内存映射的程序,需求如下:
- 将文件中的大小写字母互换
- 数字替换为
*** - 修改后的内容写回原文件
- 父进程负责字母大小写转换,子进程负责数字替换,分前后两半依次处理文件
目前前半部分处理正常,但后半部分数据损坏。我尝试将buffer改为char*类型,以及代码中注释的多种方法,均未解决问题。
代码实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <signal.h> #include <sys/wait.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char **argv) { // 检查是否提供了文件名参数 if (argc < 2) { printf("Error: se debe proporcionar el nombre del archivo como argumento.\n"); exit(EXIT_FAILURE); } // 以读写模式打开文件 int file = open(argv[1], O_RDWR); if (file < 0) { printf("Error: no se puede abrir el archivo %s.\n", argv[1]); exit(EXIT_FAILURE); } // 获取文件状态 struct stat estado; if (fstat(file, &estado) < 0) { printf("Error: no se puede obtener el estado del archivo %s.\n", argv[1]); exit(EXIT_FAILURE);// 接收信号时执行的函数 } // 检查是否为普通文件 if (!S_ISREG(estado.st_mode)) { printf("Error: %s no es un archivo regular.\n", argv[1]); exit(EXIT_FAILURE); } // 将文件映射到内存 char *map = (char*) mmap(NULL, estado.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0); if (map == MAP_FAILED) { printf("Error: no se puede mapear el archivo %s en memoria.\n", argv[1]); exit(EXIT_FAILURE); } printf("\n---------------PROCESO DE LECTURA EN CURSO---------------\n"); char texto ='\0'; int lr = 0; for (int i = 0; i < estado.st_size; i++) { // 开始读取文件 if ((lr = read(file, &texto, 1)) < 0) { printf("\nError intentando leer el archivo\n"); exit(EXIT_FAILURE); } // 检查文件内容是否读取正确 printf("%c", texto); } // 创建子进程 pid_t pid = fork(); if (pid < 0) { printf("Error: no se puede crear el proceso hijo.\n"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程 // 等待父进程处理完文件的一半 raise(SIGSTOP); // 暂停进程等待父进程信号 int mitadArchivo = estado.st_size / 2; // 计算替换数字后的文件最终大小 int tamanioFinal = estado.st_size; for (int i = 0; i < estado.st_size; i++) { if (isdigit(map[i])) { tamanioFinal += 2; } } // 调整文件大小以匹配最终大小 if (ftruncate(file, tamanioFinal) < 0) { printf("Error: no se puede redimensionar el archivo %s.\n", argv[1]); exit(EXIT_FAILURE); } // 处理文件的后半部分 char buffer[/*mitadArchivo*/estado.st_size]; int j = 0, k = 0; printf("\n---------IMPRIMIR DESDE EL HIJO---------\n"); for (int i = 0; i < estado.st_size; i++) { if (isdigit(map[i])) { // 如果是数字,替换为三个星号 buffer[j++] = '*'; buffer[j++] = '*'; buffer[j++] = '*'; } else { // 非数字则直接复制到buffer buffer[j++] = map[i]; } printf("%c", buffer[i]); if (i == mitadArchivo) { // 到达文件中点 memcpy(map, buffer, /*2*(estado.st_size + j)*/ mitadArchivo + j); // 写入修改后的前半部分 raise(SIGSTOP); // 暂停进程等待父进程信号 printf("\nSegunda mitad del archivo: \n"); if (isdigit(map[i])) { // 如果是数字,替换为三个星号 buffer[k++] = '*'; buffer[k++] = '*'; buffer[k++] = '*'; } else { // 非数字则直接复制到buffer buffer[k++] = map[i]; } memcpy(buffer, map + (mitadArchivo + j), /*2*(estado.st_size + j)*/ tamanioFinal - (mitadArchivo + j)); // 读取待处理的后半部分 } } printf("\n"); // 将buffer内容复制到文件 //memcpy(map /*+ mitadArchivo*/, buffer, j); // 修改文件大小以适应更改 //ftruncate(file, 2*(estado.st_size + j) /*- mitadArchivo*/); // 子进程退出 exit(EXIT_SUCCESS); } else { // 父进程 // 处理文件的前半部分 char buffer[estado.st_size]; int mitadArchivo = estado.st_size / 2; int j = 0; for (int i = 0; i < estado.st_size /*/ 2*/; i++) { if (islower(map[i])) { // 小写字母转大写 buffer[j++] = toupper(map[i]); } else if (isupper(map[i])) { // 大写字母转小写 buffer[j++] = tolower(map[i]); } else { // 非字母直接复制到buffer buffer[j++] = map[i]; } if (i == estado.st_size / 2){ sleep(1); // 将buffer内容复制到文件 memcpy(map, buffer, j); // 通知子进程继续执行 kill(pid, SIGCONT); } } // 将buffer内容复制到文件 memcpy(buffer, map, j); sleep(1); // 通知子进程继续执行 kill(pid, SIGCONT); // 等待子进程结束 waitpid(pid, NULL, 0); printf("\n---------IMPRIMIR DESDE LA SALIDA DESDE MEMORIA---------\n"); for (int i = 0; i < estado.st_size; i++) printf("%c", map[i]); printf("\n"); // 父进程退出 exit(EXIT_SUCCESS); } return 0; }
运行输出
---------------PROCESO DE LECTURA EN CURSO--------------- esta 5 es 6 la prueba 89 para 531 ver si 35 el programa 7 funciona ---------IMPRIMIR DESDE EL HIJO--------- ESTA *** ES *** LA PRUEBA ****** P Segunda mitad del archivo: ARA ********* ARA ********* ���c� ---------IMPRIMIR DESDE LA SALIDA DESDE MEMORIA--------- ESTA *** ES *** LA PRUEBA ****** PARA ********* ���c���of�/����
内容的提问来源于stack exchange,提问作者Ant
相关产品推荐
相关产品推荐

