Fórum Como usar arrays dinâmicos em memória compartilhada IPC #412743

13/02/2012

0

Olá,

Estou trabalhando em um projeto que é composto por dois aplicativos: um servidor de dados e um cliente multi-instância que exibe os dados do servidor para o usuário. Para realizar o compartilhamento entre os aplicativos, resolvi usar o compartilhamento de memória (IPC) do Windows, pois o volume de dados trafegado é muito grande e não conheço outro meio que seria tão eficiente.

A tecnologia funciona perfeitamente para estruturas de dados simples, como um record com tipos primitivos, por exemplo. O problema é que eu preciso compartilhar arrays de tamanho variável entre os aplicativos. Obviamente, isso não poderia ser feito do jeito tradicional de criar arrays dinâmicos, como usando a função New, então o que pensei foi em usar um estilo C de programar pra ver se funcionava.

Eu não diria que eu fui bem sucedido nessa tentativa, mas também não achei a solução ideal. O que tentei foi criar uma área de memória compartilhada com o tamanho do meu array e depois apontar minha variável do array para essa área de memória. O que esperava é que o array fosse definido para a posição com o tamanho correto, mas não aconteceu. Eu consigo apontar o array para aquela área de memória mas o tamanho dele fica muito grande (algo em torno de 131000 posições). Se tento usar a função SetLength nele, uma exceção AccessViolation é lançada. O que queria saber é se existe alguma outra maneira de mudar o tamanho de um array que não seja essa função, como no C com arrays null-terminated.

Mas então... essa foi a parte mal sucedida. A parte que deu certo foi que eu consegui acessar essa área de memória corretamente usando apontadores e percorrendo-a na mão, o que quer dizer que estou acessando a área correta, só preciso conseguir manipular o array corretamente. Essa solução, utilizando ponteiros e manipulando seu acesso manualmente, é até viável, mas acredito que não muito elegante, por isso queria utilizar os arrays.

Segue o código de como estou criando e depois tentando abrir (já em outro aplicativo) a área de memória compartilhada (retirei algumas partes irrelevantes para essa discussão para diminuir o tamanho, como verificações de integridade e etc.):

TSharedData = record
  Id: Integer;
  ...
end;


procedure CreateData;
var
  SA: TSecurityAttributes;
  SD: PSecurityDescriptor;
begin
  New(SD);

  InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(SD, True, nil, False);
  SA.nLength := SizeOf(TSecurityAttributes);
  SA.bInheritHandle := True;
  SA.lpSecurityDescriptor := SD;

  // Cria memória compartilhada
  HSharedData := CreateFileMapping($FFFFFFFF, @SA,
    PAGE_READWRITE, 0, SizeOf(TSharedData) + MAX_VETOR * SizeOf(Single), // aloca o tamanho do record mais o tamanho do array
    SharedData);

  // Mapeia memória compartilhada
  SharedData := MapViewOfFile(HSharedData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
end;


procedure OpenData;
var
  MeuArray: array of Single;
begin
  // Abre a memória compartilhada.
  HSharedData := OpenFileMapping(FILE_MAP_ALL_ACCESS,
    False, SharedData);

  // Mapeia memória compartilhada
  SharedData := MapViewOfFile(HSharedData,
    FILE_MAP_ALL_ACCESS, 0, 0, 0);

  // O array fica depois do record na memória
  MeuArray := Pointer(Integer(SharedData) + SizeOf(TSharedData));
  SetLength(MeuArray, MAX_VETOR); // Aqui lança AccessViolation
end;
Frederico Meira

Frederico Meira

Responder

Posts

13/02/2012

Marco Salles

qual a definição tipo de

HSharedData
SharedData
MAX_VETOR

??
Responder

Gostei + 0

14/02/2012

Frederico Meira

Me desculpe, esqueci alguns detalhes...

type
  PSharedData = ^TSharedData;
var
  HSharedData: THandle;
  SharedData: PSharedData;


A constante MAX_VETOR está sendo usada como teste, para informar o tamanho do array, mas no aplicativo real esse tamanho será dado por uma variável.
Responder

Gostei + 0

15/02/2012

Frederico Meira

Caros,

Consegui resolver meu problema de definir o tamanho de um vetor sem a função SetLength. Descobri que o tamanho de um vetor é um inteiro que reside na área de memória logo anterior ao ponteiro do vetor. Então, por exemplo, se seu vetor aponta para 0x100A, seu tamanho estará 4 bytes para trás, em 0x1006.

Essa informação já resolveu meu problema, e como não consegui encontrá-la em lugar algum, achei interessante postá-la para vocês.

Aquele abraço

TÓPICO RESOLVIDO
Responder

Gostei + 0

17/02/2012

Marco Salles

que bom que voce resolveru e melhor ainda por compartilhar como resolveu
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar