Блог по программированию в среде Delphi

Поиск по блогу

Есть идея по созданию интересной программы?

Опиши тут и я по возможности постараюсь это реализовать специально для тебя! Без $ ))

четверг, 18 ноября 2010 г.

Создание именованной, совместно используемой памяти (Delphi)

Отображение файла в память для совместного использования несколькими процессами.



Первый процесс создает файл Temp.txt, после чего проецирует его в память

//первый процесс
unit mainServ;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;


type
  TForm1 = class(TForm)
    btnCreate: TButton;
    Memo1: TMemo;
    procedure btnCreateClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);

  private
    { Private declarations }
  public
    { Public declarations }
  end;
const
  MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
  bufSize=100;//размер буфера

var
  Form1: TForm1;
  hFile,hMapedFile:HWND;
  pMapFile:Pointer;

implementation

{$R *.dfm}

//Создание именованной, совместно используемой памяти
procedure TForm1.btnCreateClick(Sender: TObject);
var
  outBuff:array[0..bufSize] of Char;
  byteWrt:Cardinal;
begin
  if not Assigned(pMapFile) then
    UnmapViewOfFile(pMapFile);
  if hMapedFile<>INVALID_HANDLE_VALUE then
    CloseHandle(hMapedFile);
  if (hFile<>INVALID_HANDLE_VALUE) then
    CloseHandle(hFile);
  hFile:=CreateFile(PWideChar('Temp.txt'),
                    GENERIC_READ or GENERIC_WRITE,
                    FILE_SHARE_READ or FILE_SHARE_WRITE,
                    nil,CREATE_ALWAYS or OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,0);

  if hFile=INVALID_HANDLE_VALUE then
  begin
    ShowMessage('Ошибка при создании файла '+SysErrorMessage(GetLastError));
    Exit;
  end;
  StrPCopy(outBuff,Memo1.Lines.Text);
  WriteFile(hFile,outBuff,bufSize*SizeOf(Char),byteWrt,nil);

  hMapedFile:=CreateFileMapping(hFile,                //INVALID_HANDLE_VALUE-использование файла подкачки
                                nil,                  // защита по умолчанию
                                PAGE_READWRITE,       //доступ к чтению/записи
                                0,                    // макс. размер объекта
                                bufSize*SizeOf(Char), // размер буфера
                                MMFName);             // имя отраженного в памяти объекта

  if hMapedFile=INVALID_HANDLE_VALUE then
  begin
    ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
    CloseHandle(hFile);
    Exit;
  end;
  pMapFile:=MapViewOfFile(hMapedFile,           //дескриптор "проецируемого" объекта
                          FILE_MAP_ALL_ACCESS,  // разрешение чтения/записи
                          0,0,
                          bufSize*SizeOf(Char));//размер буфера
  if pMapFile=nil then
  begin
    ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
    CloseHandle(hMapedFile);
    CloseHandle(hFile);
    Exit;
  end;
end;


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if not Assigned(pMapFile) then
    UnmapViewOfFile(pMapFile);
  if hMapedFile<>INVALID_HANDLE_VALUE then
    CloseHandle(hMapedFile);
  if (hFile<>INVALID_HANDLE_VALUE) then
    CloseHandle(hFile);end;

end.

Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.

Второй процесс может получить доступ к одним и тем же данным при помощи вызова функции OpenFileMapping с тем же самым именем, что и первый процесс. Он может затем использовать функцию MapViewOfFile, чтобы получить указатель на представление данных файла.


//второй процесс


unit clientMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btnRead: TButton;
    Memo1: TMemo;
    procedure btnReadClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
const
  MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
  bufSize=100;//размер буфера

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnReadClick(Sender: TObject);
var
  hMapedFile:HWND;
  pMapFile:Pointer;

begin
  hMapedFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS, // доступ к чтению/записи
                              False, //имя не наследуется
                              MMFName);//имя "проецируемого " объекта

  if hMapedFile=INVALID_HANDLE_VALUE then
  begin
    ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
    Exit;
  end;

  pMapFile:=MapViewOfFile(hMapedFile,//дескриптор "проецируемого" объекта
                          FILE_MAP_ALL_ACCESS,// разрешение чтения/записи
                          0,0,
                          bufSize*SizeOf(Char));//размер буфера

  if pMapFile=nil then
  begin
    ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
    CloseHandle(hMapedFile);
    Exit;
  end;

  Memo1.Text:=PChar(pMapFile);
  UnmapViewOfFile(pMapFile);
  CloseHandle(hMapedFile);
end;

end.

Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.

Скачать проекты можно отсюда Download

2 комментария:

  1. В проекте используется локальное кеширование метаданных из БД в ini-файл. Работа с файлом происходит через обьект TCustomIniFile. Все работает быстро и красиво. Но до того момента, когда приложений несколько. Проблемы начинаются, когда через терминальный сервер подключаются десятки\сотни клиентов. Происходит неоптимальное выжирание памяти. Фактически, каждый екземпляр приложения вычитывает и кеширует одинаковый набор ini-файлов. Можна ли при помощи проекции файла в память реализовать работу с общим кешем? Или как можно организовать работу кеша, чтобы повторно использовать обьект/данные другими приложениями без ущерба производительности?

    ОтветитьУдалить
    Ответы
    1. сначала не понял смысла вопроса долго вчитывался.
      посмотрев MSDN нашел следующее:
      http://msdn.microsoft.com/en-us/library/windows/desktop/aa366551%28v=vs.85%29.aspx

      Предваряя файл сопоставления имен объектов с «Global\» позволяет процессам взаимодействовать друг с другом, даже если они находятся в различных терминальных сеансах сервера. Это требует, что первый процесс должен иметь привилегии SeCreateGlobalPrivilege.

      как я понял это то, что вам нужно!

      Удалить