将一维数组添加到 C 中的 POSIX 共享内存对象

Adding a 1-dimensional array to a POSIX Shared Memory Object in C

我正在开发一个基于 POSIX 的程序,该程序在两个或多个进程之间共享一个内存对象,也就是服务器 - 客户端程序。

程序的服务器端存在一些问题。我知道如何使用 mmap() 映射内存以及如何在两个不同的 processes/programs 之间使用对象。但是,将整数数组添加到共享内存对象时出现问题。

我可以使用sprintf()将内容打印到共享内存对象,然后通过简单地说ptr += strlen(whatstringiamworkingwith);[=15=来增加(重新分配)共享内存对象的space ]

但是,我不知道如何在 C 中为包含整数数组的对象重新分配内存。这是我的程序:

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

int *calcCollatz(int n) {
    int solution;

    int *collatzSeq = malloc(sizeof(int));
    int j = 0;

    while (n != 1) {
        if (n % 2 == 0) {
            solution = n / 2;
            n = solution;
            collatzSeq[j] = n;
            j++;
            return collatzSeq;
        } else {
            solution = (3 * n) + 1;
            n = solution;
            collatzSeq[j] = n;
            j++;
            return collatzSeq;
        }
    }
}

int main(int argc, char *argv[])
{
    const int SIZE = 4096;          //size in bytes of Shared Memory Object
    const char *sharedObj = "Shm";  //name of the Shared memory Object
    int shm_fd;                     //Shared memory file descriptor
    void *ptrShm; //Pointer to shared memory object

    shm_fd = shm_open(sharedObj, O_CREAT | O_RDWR, 0666); //Create Shared Memory Object
    ftruncate(shm_fd, SIZE);  //configure the size of the shared memory object
                              //Map the shared memory object in the space of the process
    ptrShm = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);

    if (ptrShm == MAP_FAILED) {
        printf("Map Failed\n");
        return -1;
    }

    sprintf(ptrShm, argv[1]);
    ptrShm += strlen(argv[1]);

    sprintf(ptrShm, calcCollatz(atoi(argv[1])));
    ptrShm += sizeof(calcCollatz(atoi(argv[1])));


    printf("Writing the sequence to a shared memory object!\n");
    return 0;
}

我走在正确的轨道上吗?

您的代码中存在一些错误和问题。

  1. ptr += strlen(whatstringiamworkingwith);是推进一个指针,不是 重新分配内存。

  2. sprintf(ptrShm, argv[1]);是危险的,如果我执行你的程序 像这样: ./yourprogram %s 那么你将有未定义的行为作为 %s 说明符将存在,但指向 char* 以满足说明符的指针是 丢失的。切勿将用户填写的变量作为 printf & 的格式传递 Co. 所以这样做:

    sprintf(ptrShm, "%s", argv[1]);
    

    这条线也一样:sprintf(ptrShm, calcCollatz(atoi(argv[1])));

    而且你没有检查是否有足够的命令行参数,你应该 在程序的开头添加:

    if(argc != 2)
    {
        fprintf(stderr, "usage: %s data\n", argv[0]);
        return 1;
    }
    
  3. 错误消息应该打印到 stderr,所以不要这样做 printf("Map Failed\n"); 你应该这样做:

    fprintf(stderr, "Map failed\n");
    

    但这不是很有用,您还应该打印 errno 的值 像这样:

    fprintf(stderr, "Map failed: %s\n", strerrno(errno));
    // or
    perror("Map failed");
    
  4. 您没有检查 return 值 shm_open

  5. 退出代码是有符号的 8 位值,所以 return -1 相当于 return 255.

  6. shm_open 手册页所述:

    man shm_open

    a shared memory object should be identified by a name of the form /somename; that is, a null-terminated string of up to NAME_MAX (i.e., 255) characters consisting of an initial slash, followed by one or more characters, none of which are slashes.

    所以正确的名字应该是

    const char *sharedObj = "/Shm";
    
  7. sizeof(calcCollatz(atoi(argv[1])));sizeof(int*)相同,即 表示指向 int 的指针的大小。并且因为 sizeof 是在 compile-time,该函数实际上从未执行过。您可能想按数字调整大小 项目。不仅 ptr += size 是错误的调用,而且您得到了 信息完全错误。

    你的calcCollatz也是错误的,你只分配了space一个 int,为什么要为单个 int 动态分配 space? 另外,你马上就在做 return collatzSeq,又何必呢? 为单个 int 动态分配 space?我想这就是你 寻找:

    int *calcCollatz(int n, size_t *len) {
        if(len == NULL)
            return NULL;
    
        int *collatzSeq = NULL, *tmp = NULL;
        *len = 0;
    
        while (n != 1) {
            // better than n % 2 == 0
            if (n & 1 == 0)
                n /= 2;
            else
                n = 3 * n + 1;
    
            tmp = realloc(collatzSeq, (*len + 1) * sizeof *collatzSeq);
            if(tmp == NULL)
            {
                free(collatzSeq);
                return NULL;
            }
            collatzSeq = tmp;
    
            collatzSeq[(*len)++] = n;
        }
    
        return collatzSeq;
    }
    
  8. 我不太明白你为什么要调整mmap内存。通常你 立即知道您需要多少内存以及是否需要动态存储 生成数组,然后计算你需要的内存量,然后创建 共享内存,而不是相反:

    size_t base = 4096;
    size_t arrlen;
    
    int *arr = calcCollatz(atoi(argv[1]), &arrlen);
    if(arr == NULL)
    {
        fprintf(stderr, "failed to do calculation\n");
        return 1;
    }
    
    size_t size = base + arrlen;
    
    shm_fd = shm_open(sharedObj, O_CREAT | O_RDWR, 0666);
    if(shm_fd == -1)
    {
        fprintf(stderr, "Failed to open shared memory: %s\n", strerror(errno));
        return 1;
    }
    ftruncate(shm_fd, size);
    
    ptrShm = mmap(0, size, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    
    if (ptrShm == MAP_FAILED) {
        fprintf(stderr, "Map Failed: %s\n", strerror(errno));
        return 1;
    }
    
    printf("Writing the sequence to a shared memory object!\n");
    sprintf(ptrShm, "%s", argv[1]);
    
    // note that void* arithmetic is a GNU extension
    // otherwise you have to cast to (char*) before doing the
    // the arithmetic
    memcpy(ptrShm + base, arr, arrlen * sizeof *arr);
    
    free(arr);
    close(shm_fd);
    return 0;
    

    但是如果你以后坚持调整mmap内存的大小,那么你可以使用 mremap,但请注意,这仅在 GNU/Linux 中可用,而且您 必须在包含 sys/mman.h:

    之前添加 #define _GNU_SOURCE
    size_t size = 4096;
    
    // create shared memory + mmap
    ...
    
    // exapanding mmap memory
    size_t arrlen;
    
    int *arr = calcCollatz(atoi(argv[1]), &arrlen);
    if(arr == NULL)
    {
        fprintf(stderr, "failed to do calculation\n");
        close(shm_fd);
        return 1;
    }
    
    size_t newsize = size + arrlen * sizeof *arr;
    
    void *newptrShm = mremap(ptrShm, size, newsize, MREMAP_MAYMOVE);
    
    if(newptrShm == MAP_FAILED)
    {
        fprintf(stderr, "Failed to expand memory: %s\n", strerror(errno));
        free(arr);
        close(shm_fd);
        return 1;
    }
    
    ptrShm = newptrShm;
    
    // resize shared file size
    ftruncate(shm_fd, newsize);
    
    memcpy(ptrShm + base, arr, arrlen * sizeof *arr);
    
    free(arr);
    
    ...
    

    另请参阅:Fast resize of a mmap fileHow to portably extend a file accessed using mmap()