我正在开发基于 gstreamer 的流媒体应用程序。我根据项目要求创建了一组 gstreamer 插件。我面临着在主应用程序和 gstreamer 插件之一之间共享数据的挑战。我尝试过不同的 IPC 机制,例如文件、namedPipes 和消息队列。这些 IPC 机制无法解决我的问题。我终于使用共享内存将数据从主应用程序传输到插件。我需要传递一个包含 4-5 个整数数组变量的结构数据。
我的主要应用程序是数据的生产者,插件是消费者。
以下代码是给制作人的:
#ifndef __IPC_SHMW__
#define __IPC_SHMW__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
typedef struct {
int x[20];
int y[20];
int w[20];
int h[20];
int num;
} send_data_WR;
class IPC_DATA_SEND {
public:
int shmid;
key_t key = 1996;
send_data_WR *_data;
int create_shm(){
shmid = shmget(key, sizeof(send_data_WR), IPC_CREAT | 0666);
printf("SHMID Write Process %d \n",shmid);
if (shmid < 0) {
perror("shmget");
exit(1);
}
_data = (send_data_WR*) shmat(shmid, NULL, 0);
if (_data == (send_data_WR *) -1) {
perror("shmat");
exit(1);
}
//std::cout << "SHMID Write Address " << _data << std::endl;
printf("SHMID Write Address %x \n", _data);
}
int write_data(send_data_WR * data){
_data->num = data->num;
for(int i=0; i<data->num; i++){
_data->x[i] = data->x[i];
_data->y[i] = data->y[i];
_data->w[i] = data->w[i];
_data->h[i] = data->h[i];
printf("Write: x=%d y=%d w=%d h=%d \n", _data->x[i], _data->y[i], _data->w[i], _data->h[i]);
}
sleep(1);
return 0;
}
int clean_shm(){
// Detach shared memory segment
shmdt(_data);
// Remove shared memory segment
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
};
#endif
以下代码用于消费者插件:
#ifndef __IPC_SHMR__
#define __IPC_SHMR__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
typedef struct {
int x[20];
int y[20];
int w[20];
int h[20];
int num;
} read_data_WR;
class IPC_DATA_READ {
public:
int shmid;
key_t key = 1996;
read_data_WR *_data;
int read_shm(){
shmid = shmget(key, sizeof(read_data_WR), 0);
printf("SHMID Read Process %d \n",shmid);
if (shmid < 0) {
perror("shmget");
exit(1);
}
_data = (read_data_WR*) shmat(shmid, NULL, 0);
if (_data == (read_data_WR *) -1) {
perror("shmat");
exit(1);
}
printf("SHMID Read Address %x \n",_data);
}
int read_data(read_data_WR * data){
printf("Inside Read Data SHM \n");
printf("[Read SHM] num = %d \n", _data->num);
data->num = _data->num;
printf("[Read SHM] data num = %d \n", data->num);
for(int i=0; i<data->num; i++){
data->x[i] = _data->x[i];
data->y[i] = _data->y[i];
data->w[i] = _data->w[i];
data->h[i] = _data->h[i];
printf("Read: x=%d y=%d w=%d h=%d \n", data->x[i], data->y[i], data->w[i], data->h[i]);
}
return 0;
}
int clean_shm(){
// Detach shared memory segment
shmdt(_data);
// Remove shared memory segment
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
};
#endif //__IPC_SHMR__
编译没有问题。代码编译成功,当我启动主应用程序时,生产者代码开始写入共享内存区域。
我可以通过一组打印语句来验证它。但是,当我开始使用我的插件(消费者)时,没有可用数据。打印语句只打印 0.
我检查了 fd 和每个进程的指针指向的数据的地址位置,我看到 fd 有不同的值,指针指向不同的地址。
SHMID Write Process 0
SHMID Write Address 8a087000
...
SHMID Read Process 1
SHMID Read Address 8a05c000
我试着弄清楚可能是什么问题。
我没有在网上找到任何解决方案,也无法找到问题的根本原因。有人可以帮助我理解我做错了什么吗?
谢谢
编辑:它对我有效,见下文
2 评论你的问题:
shmid
,奇怪的是它在消费者/生产者中没有返回相同的值(在我这边你会看到我正确地有两次相同的shmid
)编辑:我在我这边运行你的代码并且它有效,我用它作为消费者的主要(这里有一个内存泄漏要修复,它只是为了测试:
int main(){
std::cout << "Producer" << std::endl;
IPC_DATA_SEND dataC;
dataC.create_shm();
send_data_WR* theData = new send_data_WR();
theData->num=4;
theData->x[3]=5;
dataC.write_data(theData);
}
输出:
> g++ -std=c++11 shmem.cpp -o shmem
> ./shmem
Producer
SHMID Write Process 65536
SHMID Write Address 9c842000
Write: x=0 y=0 w=0 h=0
Write: x=0 y=0 w=0 h=0
Write: x=0 y=0 w=0 h=0
Write: x=5 y=0 w=0 h=0
对于读者,我修改了
read_data()
功能以使其更直接:
int read_data(){
printf("Inside Read Data SHM \n");
printf("[Read SHM] num = %d \n", _data->num);
for(int i=0; i<_data->num; i++){
printf("Read: x=%d y=%d w=%d h=%d \n", _data->x[i], _data->y[i], _data->w[i], _data->h[i]);
}
return 0;
}
主要是:
int main(){
std::cout << "Consumer" << std::endl;
IPC_DATA_READ dataR;
dataR.read_shm();
dataR.read_data();
}
输出是:
> g++ -std=c++11 shmem_read.cpp -o shmem_read
> ./shmem_read
Consumer
SHMID Read Process 65536
SHMID Read Address a1351000
Inside Read Data SHM
[Read SHM] num = 4
Read: x=0 y=0 w=0 h=0
Read: x=0 y=0 w=0 h=0
Read: x=0 y=0 w=0 h=0
Read: x=5 y=0 w=0 h=0
我也没有清理共享内存,为了手动清理它,在 linux 上你可以使用
ipcs
识别 shmem id 和 ipcrm -m <shmem_id>
删除它