C - 多进程的内存映射

标签 c memory mapping mmap

我有一项作业,要求我编写一个多处理程序,该程序可处理包含字符串的内存映射文件。父进程将文件映射到内存后,会生成2个子进程来修改文件。子进程 1 输出文件的内容,将文件的内容转换为大写形式,然后输出文件的新内容。子进程 2 等待 1 秒让子进程 1 完成,输出文件的内容,删除所有连字符“-”,然后输出文件的新内容。我对两个子进程的问题是,在第一次显示文件的内容后,进程尝试修改文件的内容,但两个子进程都不会输出文件的新内容。我在运行或编译时没有收到错误,所以我无法找出问题所在。当然,我是内存映射的新手,所以请随时让我知道我做错了什么。这是我的源代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <string.h>

int main (int argc, char *argv[]) { 
    struct stat buf;
    int fd, length, status, i, j, k;
    char *mm_file;
    char *string = "this is a lowercase-sentence.";
    length = strlen(string);

    fd = open(argv[1], O_CREAT | O_RDWR, 0666); //Creates file with name given at command line
    write(fd, string, strlen(string)); //Writes the string to be modified to the file
    fstat(fd, &buf); //used to determine the size of the file

    //Establishes the mapping
    if ((mm_file = mmap(0, (size_t) buf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (caddr_t) - 1) {
       fprintf(stderr, "mmap call fails\n");
    }

    //Initializes child processes
    pid_t MC0;
    pid_t MC1;

    //Creates series of child processes which share the same parent ID
    if((MC0 = fork()) == 0) {
        printf("Child 1 %d reads: \n %s\n", getpid(), mm_file);
        //{convert file content to uppercase string};
        for (i = 0; i < length; i++) {
            string[i] = toupper(string[i]);
        }
        //sync the new contents to the file
        msync(0, (size_t) buf.st_size, MS_SYNC);
        printf("Child 1 %d reads again: \n %s\n", getpid(), mm_file);
        exit(EXIT_SUCCESS); //Exits process
    } else if ((MC1 = fork()) == 0) {
        sleep(1); //so that child 2 will perform its task after child 1 finishes
        ("Child 2 %d reads: \n %s\n", getpid(), mm_file);
        //{remove hyphens}
        for (j = 0; j < length; i++) {
            if (string[i] == '-') {
                string[i] = ' ';
            }
        }
        //sync the new contents to the file
        msync(0, (size_t) buf.st_size, MS_SYNC);
        printf("Child 2 %d reads again: \n %s\n", getpid(), mm_file);
        exit(EXIT_SUCCESS); //Exits process
   } 

   // Waits for all child processes to finish before continuing.
   waitpid(MC0, &status, 0);
   waitpid(MC1, &status, 0);

   return 0;
}

那么我的输出如下:

**virtual-machine:~$** ./testt file

Child 1 3404 reads: 

this is a lowercase-sentence.

Child 2 3405 reads: 

this is a lowercase-sentence.

All child processes have finished. Now exiting program.

**virtual-machine:~$**

但我想要的结果是:

**virtual-machine:~$** ./testt file

Child 1 3404 reads: 

this is a lowercase-sentence.

Child 1 3404 reads again: 

THIS IS A LOWERCASE-SENTENCE.

Child 2 3405 reads: 

THIS IS A LOWERCASE-SENTENCE.

Child 2 3405 reads: 

THIS IS A LOWERCASE SENTENCE.

All child processes have finished. Now exiting program.

**virtual-machine:~$**

非常感谢任何帮助。

最佳答案

这里有一些错误。首先,写入文件,然后将其映射到内存中。映射是正确的,但书写不正确。如果字符串有 n 个字符,则必须编写 n+1 个字符,因为 C 中的字符串以 null 结尾。现在你只有 n,所以所有 C 字符串函数都会尝试访问至少一个字节,这是不好的。如果那个额外的字节不为空(零),则函数将走得更远。在更多调试中,它们可能会被清零,但在优化代码中通常不会。所以你必须使用

write(fd, string, strlen(string)+1); //Writes the string to be modified to the file

然后你这样做:

    for (i = 0; i < length; i++) {
        string[i] = toupper(string[i]);
    }

这只改变指针string引用的数据,与内存映射文件无关。你应该有:

    for (i = 0; i < length; i++) {
        mm_file[i] = toupper(mm_file[i]);
    }

第二个子进程也是如此。

此外,您的 msync() 调用也有点可疑。您将内存地址指定为 0,该地址不在内存映射文件内,因此它不会同步内容。您需要调用msync(mm_file, (size_t) buf.st_size, MS_SYNC);

此外,许多编译器会将常量字符串放入只读内存中,因此您甚至可能不允许更改 string 引用的数据。在这种情况下,您似乎被允许。

还请记住,文件的长度比字符串的长度大一个字节,因此请正确使用变量。目前您可以这样做,因为您将文件与文件长度同步并使用字符串长度处理字符串。

关于C - 多进程的内存映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29910878/

相关文章:

python - 查找复杂列表中的最大值 - Python

c++ - 如何评估预处理器宏中的参数以传递给 sizeof?

c - 如何使用 cairo 确定 Gtk+ 3 中的非矩形绘图区域?

c++ - 使用 recvfrom 获取数据

java 堆内存更改后 MATLAB 将无法打开

nhibernate - 流畅的 NHibernate - NHibernate.QueryException : could not resolve property

c - fseek/ftell 和 stat.st_size 在文本模式下不返回实际文件大小

ajax - uiComponent树内存使用情况

performance - double 运算 : 32-bit vs 64-bit machines

c++ - 将对象交换到文件