将一维数组添加到 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;
}
我走在正确的轨道上吗?
您的代码中存在一些错误和问题。
ptr += strlen(whatstringiamworkingwith);
是推进一个指针,不是
重新分配内存。
做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;
}
错误消息应该打印到 stderr
,所以不要这样做
printf("Map Failed\n");
你应该这样做:
fprintf(stderr, "Map failed\n");
但这不是很有用,您还应该打印 errno
的值
像这样:
fprintf(stderr, "Map failed: %s\n", strerrno(errno));
// or
perror("Map failed");
您没有检查 return 值 shm_open
。
退出代码是有符号的 8 位值,所以 return -1
相当于
return 255
.
如 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";
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;
}
我不太明白你为什么要调整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 file 和
How to portably extend a file accessed using mmap()
我正在开发一个基于 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;
}
我走在正确的轨道上吗?
您的代码中存在一些错误和问题。
ptr += strlen(whatstringiamworkingwith);
是推进一个指针,不是 重新分配内存。做
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; }
错误消息应该打印到
stderr
,所以不要这样做printf("Map Failed\n");
你应该这样做:fprintf(stderr, "Map failed\n");
但这不是很有用,您还应该打印
errno
的值 像这样:fprintf(stderr, "Map failed: %s\n", strerrno(errno)); // or perror("Map failed");
您没有检查 return 值
shm_open
。退出代码是有符号的 8 位值,所以
return -1
相当于return 255
.如
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";
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; }
我不太明白你为什么要调整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 file 和 How to portably extend a file accessed using
mmap()