Cómo usar la memoria compartida de Linux y la memoria compartida Qt QSharedMemory, ¿sabes cómo usarla hoy?

1. Comunicación del proceso de Linux

Hay muchas formas de comunicarse entre procesos en sistemas Linux:

  • tubo
  • Tubería con nombre (FIFO)
  • mapeo de memoria (mappedmemeory)
  • cola de mensajes
  • memoria compartida
  • semáforo
  • señal
  • Enchufe

La memoria compartida permite que dos o más procesos accedan a la misma memoria. Compartir memoria es un método relativamente simple y conveniente de usar. Para la comunicación de datos simple y el intercambio de archivos, compartir memoria es muy conveniente. Hablando de compartir memoria, debemos mencionar el intercambio de memoria entre subprocesos múltiples y procesos múltiples. La memoria se comparte entre subprocesos. Estrictamente hablando, los subprocesos en el mismo proceso usan el mismo espacio de direcciones, en lugar de compartir memoria entre diferentes espacios de direcciones; la memoria se comparte entre procesos padre e hijo. El proceso padre asigna una memoria anónima con la opción MAP_SHARED|MAP_ANONYMOUS. Después de la bifurcación, esta memoria se puede compartir entre sus procesos descendientes.

2. Uso de memoria compartida de Linux

Hay varias formas diferentes de implementar el uso compartido de memoria en Linux.

  • Memoria compartida basada en SYS V tradicional;
  • Implementar memoria compartida basada en el mapeo de archivos mmap POSIX;
  • La memoria compartida se implementa mediante memfd_create() y fd entre procesos compartidos;
    aquí nos centramos en la memoria compartida de SYS V.
    Primero, comprendamos el principio de la memoria compartida:
    Insertar descripción de la imagen aquí
    cuando dos o más procesos asignan la dirección de la memoria virtual a la física a través de la tabla de páginas, hay una parte de la memoria a la que se puede acceder juntos en la dirección física, que es el área de memoria compartida. . Los procesos A y B pueden operar esta área para intercambiar datos.

1. Pasos de uso básicos

  • Generar valor clave
key_t ftok(const char *path ,int id);
  • Crear un área de memoria compartida
int shmget(key_t key, size_t size, int shmflg);
  • Mapa del área de memoria compartida
void *shmat(int shmid, const void *shmaddr, int shmflg);
  • Desasignar
int shmdt(const void *shmaddr);
  • Eliminar área de memoria compartida
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

2. Escribir datos compartidos

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>

int main()
{
    
    
  key_t key = ftok(".",0x7777);
  if(key < 0)
  {
    
    
    perror("ftok failed");
    return -1;
  }
  //创建共享内存
  int shmid = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);
  if(shmid<0)
  {
    
    
    perror("shmget failed");
  }

  //映射,将共享内存挂接到进程地址空间
  char* buf = shmat(shmid,NULL,0);

  int i=0;
  memset(buf,'\0',sizeof(buf));
  strcat(buf,"第六天魔王,");

  //分离去关联
  shmdt(buf);

  //等待输入退出
  while(getchar() == '\0');

  //删除共享内存
  shmctl(shmid,IPC_RMID,NULL);
  return 0;
}

3. Leer datos compartidos

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>

int main()
{
    
    
  key_t key = ftok(".",0x7777);
  if(key < 0)
  {
    
    
    perror("ftok failed");
    return 1;
  }
  //创建共享内存
  int shmid = shmget(key,4096,IPC_CREAT);
  if(shmid<0)
  {
    
    
    perror("shmget failed");
    return 2;
  }
  //映射共享内存区
  char* buf = shmat(shmid,NULL,0);
  //读取共享数据
  printf("read shm data: %s\n",buf);  
  //分离去关联
  shmdt(buf);

  return 0;
}

Compile el archivo: gcc -o xxx xxx.c.
Primero escriba y escriba los datos en el área compartida.
Insertar descripción de la imagen aquí
Utilice el comando ipcs -m para leer la información relacionada con la memoria compartida del sistema. Realizar una lectura desde la memoria compartida.
Insertar descripción de la imagen aquí
Podemos ver que se crea un área compartida de 4096 bytes en la clave principal 0x7701a32 y el permiso es 666. La cantidad de conexiones cambiará cuando un proceso acceda a ella. Si el área de memoria compartida ya existe, se informará un error si la crea nuevamente. Si necesita eliminar el área compartida, debe ejecutar la función
int shmctl (int shmid, int cmd, struct shmid_ds *buf);
por supuesto , también puedes usar el comando para eliminarlo manualmente: ipcrm - M 0x7701a32 , eliminando así el área de memoria compartida creada anteriormente.

1. La clave de valor clave puede ser generada por ftok, o se puede especificar un valor fijo.
2. Si se elimina el área compartida, acceder nuevamente a los datos leídos hará que el programa se bloquee.
3. El intercambio de memoria generalmente necesita cooperar con Semáforo para sincronización de datos.

3. Uso de la memoria compartida Qt SharedMemory

La operación de uso compartido de memoria de Qt está encapsulada en la clase SharedMemory, que es más sencilla de usar que el uso compartido de memoria nativo de Linux.

1.Introducción a la clase SharedMemory

//默认构造函数
QSharedMemory(QObject *parent = Q_NULLPTR);
//构造函数,携带key参数
QSharedMemory(const QString &key, QObject *parent = Q_NULLPTR);
//析构
~QSharedMemory();
//设置key
void setKey(const QString &key);
//返回key
QString key() const;
//设置平台特点key
void setNativeKey(const QString &key);
//返回key
QString nativeKey() const;
//创建共享内存,指定大小和读写模式
bool create(int size, AccessMode mode = ReadWrite);
//返回共享内存大小
int size() const;
//关联共享内存
bool attach(AccessMode mode = ReadWrite);
//判断是否已关联共享内存
bool isAttached() const;
//分离共享内存
bool detach();
//返回共享内存数据
void *data();
//返回const指针共享内存const数据
const void* constData() const;
//返回const指针共享内存数据
const void *data() const;
#ifndef QT_NO_SYSTEMSEMAPHORE
//锁住共享内存
bool lock();
//解锁共享内存
bool unlock();
#endif
//返回共享内存错误
SharedMemoryError error() const;
//返回共享内存错误QString类型
QString errorString() const;

El bloqueo incorporado se utiliza aquí para la sincronización de datos y, por supuesto, también se pueden utilizar semáforos para la sincronización.
Y Qt destruirá QSharedMemory directamente después del último proceso o desconexión del subproceso ().
A continuación se muestra un proceso que escribe imágenes en el área de memoria mediante el uso compartido de memoria, y otro proceso lee las imágenes y las muestra.

2. Escribir datos compartidos

void ShmWriter::WriteToShareMemory()
{
    
    
    //准备图片数据
    QImage image;
    if(!image.load(":/img/puzzle.jpg"))
    {
    
    
        qDebug()<<"load image failed!";
        return;
    }
    QBuffer buff;
    buff.open(QBuffer::WriteOnly);
    QDataStream out(&buff);
    out<<image;

    //创建共享内存对象并设置key为"ImageShm"
    mShmWriter = new QSharedMemory("ImageShm",this);
    if(mShmWriter->isAttached())
    {
    
    
        //还在连接状态则进行分离
        mShmWriter->detach();
    }
    //创建共享内存
    if(!mShmWriter->create(buff.size()))
    {
    
    
        qDebug()<<"create share memory failed!"<<mShmWriter->errorString();
        return;
    }
    //锁住共享区域
    mShmWriter->lock();
    //拷贝数据到共享内存
    char *shmAddr = (char*)mShmWriter->data();
    const QByteArray arry(buff.data());
    const char *i_data = arry.data();
    memcpy(shmAddr,i_data,buff.size());
    //解锁
    mShmWriter->unlock();
}

3. Leer datos compartidos

void ShmReader::readFromShareMemory()
{
    
    
    //锁定
    mShmReader->lock();
    //关联共享内存
    if(!mShmReader->attach())
    {
    
    
        qDebug()<<"attach failed!"<<mShmReader->errorString();
        return;
    }
    // 从共享内存中读取数据
    QBuffer buffer;
    QDataStream in(&buffer);
    QImage image;

    buffer.setData( (const char*)mShmReader->constData(),mShmReader->size());
    buffer.open(QBuffer::ReadOnly);
    in>>image;
    //解锁
    mShmReader.unlock();
    //分离共享内存
    mShmReader.detach();
    //显示
    ui->label->setPixmap(QPixmap::fromImage(image));

}

Finalmente, los datos de la imagen se leen y se muestran de la siguiente manera.
Insertar descripción de la imagen aquí
La clave de memoria compartida de Qt se puede ingresar durante la creación de instancias, o la clave se puede configurar usando la función setKey. Las claves de lectura y escritura deben ser consistentes.
Enlace de muestra de código: https://download.csdn.net/download/haohaohaihuai/12566419

Autor: Programador Feima.
Bienvenido al intercambio técnico: QQ: 255895056.
Indique la fuente de la reimpresión. Si hay algo inapropiado, corríjame.

Supongo que te gusta

Origin blog.csdn.net/haohaohaihuai/article/details/106862138
Recomendado
Clasificación