共享内存:共享内存的消费者进程不从内存区域读取数据

问题描述 投票:0回答:1

我正在开发基于 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

我试着弄清楚可能是什么问题。

我没有在网上找到任何解决方案,也无法找到问题的根本原因。有人可以帮助我理解我做错了什么吗?

谢谢

c c++11 gstreamer shared-memory
1个回答
0
投票

编辑:它对我有效,见下文

2 评论你的问题:

  1. 你不应该有 2 个不同的
    shmid
    ,奇怪的是它在消费者/生产者中没有返回相同的值(在我这边你会看到我正确地有两次相同的
    shmid
  2. 有 2 个不同的指针是正常的,在共享内存概念中,进程之间的指针地址应该始终不同。共享内存中有相对指针和绝对指针的概念。我建议你阅读这篇文章

编辑:我在我这边运行你的代码并且它有效,我用它作为消费者的主要(这里有一个内存泄漏要修复,它只是为了测试:

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>
删除它

© www.soinside.com 2019 - 2024. All rights reserved.