最近使用多进程共享内存来实现将图像处理算法进行模块化的功能,每个处理算法对应一个进程,他们之间的数据传输通过共享内存实现,比如简单的3个图像处理预处理算法:灰度化,滤波,二值化。我们就写3个CPP文件灰度化.cpp,滤波.cpp,二值化.cpp,然后编译成灰度化.exe,滤波.exe,二值化.exe3个图像处理模块。
其运行过程大致解释为:
1.灰度化.exe模块:读取原图像->进行灰度化处理->输出灰度图像->将输出图像写入共享内存a段->退出。
2.滤波.exe模块:从共享内存a段读取灰度图像->进行滤波处理->输出滤波后的图像->将输出图像写入共享内存b段->退出。
3.二值化.exe模块:从共享内存b段读取滤波后图像->进行二值化处理->输出二值化后的图像->将输出图像写入共享内存c段待其他算法模块处理->退出。
Linux共享内存的几个API怎么用就不介绍了,这些文章已经很多了,直接上代码(注:这边的图像用文件名模拟实际的图像数据)->退出。
1.灰度化.exe模块:<gray.cpp>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#define IMAGE_BUFFER 1024 * 1024 * 3
int main(int argc, char **argv){
printf("======Gray Process======\n");
// 0.获取内存ID
int read_mem_id = atoi(argv[1]);
int write_mem_id = atoi(argv[2]);
// 1.创建写共享内存
char *myDataStruct;
void *share_memory = (void *)0; // 创建共享内存指针
int shmid = shmget((key_t)write_mem_id, IMAGE_BUFFER, 0666 | IPC_CREAT);// 开辟内存
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
share_memory = (char *)shmat(shmid, (void *)0, 0);// 映射内存
if (share_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", (int *)(share_memory));
myDataStruct = (char *)share_memory;
// 2.图像处理
char src_image_name[IMAGE_BUFFER];
char gray_image_name[IMAGE_BUFFER];
strncpy(src_image_name , "src.jpg" , strlen("src.jpg") + 1);
strncpy(gray_image_name , "gray.jpg", strlen("gray.jpg") + 1);
printf("***Read image from <%s>\n" , src_image_name);
printf("***Gray image from <%s> to <%s>\n" , src_image_name, gray_image_name);
// 3.写入处理结果到共享内存
strcpy(myDataStruct ,gray_image_name);
return 0;
}
2.滤波.exe模块:<blur.cpp>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#define IMAGE_BUFFER 1024 * 1024 * 3
int main(int argc, char **argv){
printf("======Blur Process======\n");
// 0.获取内存ID
int read_mem_id = atoi(argv[1]);
int write_mem_id = atoi(argv[2]);
// 1.创建读共享内存
char *myDataStruct;
void *share_memory = (void *)0;// 创建共享内存指针
int shmid = shmget((key_t)read_mem_id, IMAGE_BUFFER, 0666 | IPC_CREAT);// 开辟内存
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
share_memory = (char *)shmat(shmid, (void *)0, 0);// 映射内存
if (share_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", (int *)(share_memory));
myDataStruct = (char *)share_memory;
// 2.图像处理
char *gray_image_name = myDataStruct;
char blur_image_name[IMAGE_BUFFER];
strncpy(blur_image_name , "blur.jpg", strlen("blur.jpg") + 1);
printf("***Blur image from <%s> to <%s>\n" , gray_image_name, blur_image_name);
// 3.创建写共享内存
share_memory = (void *)0;// 初始化共享内存指针
shmid = shmget((key_t)write_mem_id, IMAGE_BUFFER, 0666 | IPC_CREAT);// 开辟内存
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
share_memory = (char *)shmat(shmid, (void *)0, 0);// 映射内存
if (share_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", (int *)(share_memory));
myDataStruct = (char *)share_memory;
// 4.写入处理结果到共享内存
strcpy(myDataStruct ,blur_image_name);
return 0;
}
3.二值化.exe模块:<threshold.cpp>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#define IMAGE_BUFFER 1024 * 1024 * 3
int main(int argc, char **argv){
printf("======Threshold Process======\n");
// 0.获取内存ID
int read_mem_id = atoi(argv[1]);
int write_mem_id = atoi(argv[2]);
// 1.创建读共享内存
char *myDataStruct;
void *share_memory = (void *)0;// 创建共享内存指针
int shmid = shmget((key_t)read_mem_id, IMAGE_BUFFER, 0666 | IPC_CREAT);// 开辟内存
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
share_memory = (char *)shmat(shmid, (void *)0, 0);// 映射内存
if (share_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", (int *)(share_memory));
myDataStruct = (char *)share_memory;
// 2.图像处理
char *blur_image_name = myDataStruct;
char thresh_image_name[IMAGE_BUFFER];
strncpy(thresh_image_name , "thresh.jpg", strlen("thresh.jpg") + 1);
printf("***threshold image from <%s> to <%s>\n" , blur_image_name, thresh_image_name);
// 3.创建写共享内存
share_memory = (void *)0;// 初始化共享内存指针
shmid = shmget((key_t)write_mem_id, IMAGE_BUFFER, 0666 | IPC_CREAT);// 开辟内存
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
share_memory = (char *)shmat(shmid, (void *)0, 0);// 映射内存
if (share_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", (int *)(share_memory));
myDataStruct = (char *)share_memory;
// 4.写入处理结果到共享内存
strcpy(myDataStruct ,thresh_image_name);
return 0;
}
以下是编译和运行的脚本run.sh:
#!/bin/bash
g++ gray.cpp -o gray
g++ blur.cpp -o blur
g++ threshold.cpp -o threshold
./gray 1 2
./blur 2 3
./threshold 3 4
命令行下运行./run.sh,其输出结果如下:
结果在意料之中。但是······
但是我在将共享内存的大小变大时,却出错了,我将IMAGE_BUFFER改成1024 * 1024 * 4,程序就出现段错误了,连第一句的printf打印都没打印出来,实测IMAGE_BUFFER最大值为:1024 * 1024 * 3 + 1024 * 1018,再多一个字节就出现段错误···,于是我就想是不是这个最大值可以设置,百度了一下,这个值可以通过命令:cat /proc/sys/kernel/shmmax看到(单位是字节),运行结果如下:
日了狗了,这个值这么大,为什么我将内存大小设置为1024 * 1024 * 4(4M)就报错?通过ipcs -s显示,是可以分配超过4M的,比如如下图,系统的一个共享内存就是16M的。
但是为嘛我设置成4M以上就段错误了,而且连第一句的printf都没打印出来,效果如下,希望哪位大佬可以解惑解惑!
如果哪位大佬有思路和想法,请高抬贵手为我解惑下,谢谢!