Como usar arrays dinâmicos em memória compartilhada IPC
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.):
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
Curtidas 0
Respostas
Marco Salles
13/02/2012
qual a definição tipo de
HSharedData
SharedData
MAX_VETOR
??
HSharedData
SharedData
MAX_VETOR
??
GOSTEI 0
Frederico Meira
13/02/2012
Me desculpe, esqueci alguns detalhes...
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.
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.
GOSTEI 0
Frederico Meira
13/02/2012
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
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
GOSTEI 0
Marco Salles
13/02/2012
que bom que voce resolveru e melhor ainda por compartilhar como resolveu
GOSTEI 0