Delphi内存映射文件注意新数据?

时间:2015-06-26 22:55:33

标签: delphi request communication memory-mapped-files

虽然我的问题可能是noob-ish,让我解释一下: 我最近开始玩MMF,创建2个进程,访问相同的内存指针,Process1写一个整数到MMF,Process2有一个按钮,onClick,它显示MMF中的第一个整数。

我想要做的是,当我发送"时,将数据从Process1写入MMF,Process2通知此请求,并显示准确时间的数据,依此类推,写入新数据。

我不确定线程​​检查MMF中的更改是否正常,听起来很脏。

希望有人可以指出我的解决方案,因为我没有想法:(。

这是一段代码:

 procedure OpenMap;
 var
   llInit: Boolean;
   lInt: Integer;
 begin
 if Hmapping<>0 then Exit;

   HMapping := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
                 0, MAPFILESIZE, pchar('wowsniff'));
   // Check if already exists
   llInit := (GetLastError() <> ERROR_ALREADY_EXISTS);
   if (hMapping = 0) then

     exit;

   PMapData := MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
   if PMapData = nil then
     exit;
     if (llInit) then
   begin
     // Init block to #0 if newly created
     FillChar(PMapData^, MAPFILESIZE, 0);
   end
 end;

procedure TForm1.Button3Click(Sender: TObject);
begin
LockMap;
PDword(PMapData)^:=Strtoint(edit1.Text);
UnlockMap;
end;

1 个答案:

答案 0 :(得分:3)

通过TEventCreateEvent()使用命名的事件对象。两个进程都可以创建相同的事件名称(就像创建相同的映射名称一样),然后进程1可以在写入新数据时发出事件信号,进程2可以在读取数据之前等待事件发出信号(对于实时阅读,你应该使用一个线程进行等待/阅读。

您可以通过TMutexCreateMutex()使用命名的互斥锁对象,在读取/写入数据时实现锁定/解锁功能。

尝试这样的事情:

流程1:

procedure OpenMap;
var
  llInit: Boolean;
begin
  llInit := False;

  if hMapEvent = 0 then
  begin
    hMapEvent := CreateEvent(nil, True, False, PChar('wowsniffDataReady'));
    if hMapEvent = 0 then RaiseLastOSError;
  end;

  if hMapLock = 0 then
  begin
    hMapLock := CreateMutex(nil, False, PChar('wowsniffDataLock'));
    if hMapLock = 0 then RaiseLastOSError;
  end;

  if hMapping = 0 then
  begin
    hMapping := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, MAPFILESIZE, PChar('wowsniff'));
    if hMapping = 0 then RaiseLastOSError;
    // Check if already exists
    llInit := (GetLastError() <> ERROR_ALREADY_EXISTS);
  end;

  if PMapData = nil then
  begin
    PMapData := MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, MAPFILESIZE);
    if PMapData = nil then RaiseLastOSError;

    if llInit then
    begin
      // Init block to #0 if newly created
      ZeroMemory(PMapData, MAPFILESIZE);
    end;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  LockMap;
  try
    PDword(PMapData)^ := StrToInt(Edit1.Text);
    SetEvent(hMapEvent);
  finally
    UnlockMap;
  end;
end;

procedure TForm1.LockMap;
var
  llRet: DWORD;
 begin
  llRet := WaitForSingleObject(hMapLock, 5000);
  if llRet = WAIT_OBJECT_0 then Exit;
  if llRet <> WAIT_FAILED then SetLastError(llRet);
  RaiseLastOSError;
end;

procedure TForm1.UnlockMap;
begin
  ReleaseMutex(hMapLock);
end;

流程2:

type
  TMyThread = class(TThread)
  private
    hTerminate: THandle;
    hMapLock: THandle;
    hMapEvent: THandle;
    hMapping: THandle;
    PMapData: Pointer;
  protected
    procedure Execute; override;
    procedure DoTerminate; override;
    procedure TerminatedSet; override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TMyThread.Create;
begin
  inherited Create(False);
  hTerminate := CreateEvent(nil, True, False, nil);
  if hTerminate = 0 then RaiseLastOSError;
end;

destructor TMyThread.Destroy;
begin
  if hTerminate <> 0 then CloseHandle(hTerminate)
end;

procedure TMyThread.TerminatedSet;
begin
  SetEvent(hTerminate);
end;

procedure TMyThread.Execute;
var
  llInit: Boolean;
  llRet, llValue: DWORD;
  llHandles: array[0..1] of THandle;
begin
  hMapEvent := CreateEvent(nil, True, False, PChar('wowsniffDataReady'));
  if hMapEvent = 0 then RaiseLastOSError;

  hMapLock := CreateMutex(nil, False, PChar('wowsniffDataLock'));
  if hMapLock = 0 then RaiseLastOSError;

  hMapping := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, MAPFILESIZE, PChar('wowsniff'));
  if hMapping = 0 then RaiseLastOSError;
  // Check if already exists
  llInit := (GetLastError() <> ERROR_ALREADY_EXISTS);

  PMapData := MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, MAPFILESIZE);
  if PMapData = nil then RaiseLastOSError;
  if llInit then
  begin
    // Init block to #0 if newly created
    FillChar(PMapData^, MAPFILESIZE, 0);
  end;

  llHandles[0] := hMapEvent;
  llHandles[1] := hTerminate;

  while not Terminated do
  begin
    llRet := WaitForMultipleObjects(2, PWOHandleArray(@llHandles), False, INFINITE);
    case llRet of
      WAIT_OBJECT_0+0:
      begin
        llRet := WaitForSingleObject(hMapLock, 5000);
        if llRet = WAIT_OBJECT_0 then
        begin
          try
            llValue := PDword(PMapData)^;
            ResetEvent(hMapEvent);
          finally
            ReleaseMutex(hMapLock);
          end;
          // use llValue as needed...
          Continue;
        end;
      end;
      WAIT_OBJECT_0+1:
      begin
        Exit;
      end;
    end;
    if llRet <> WAIT_FAILED then SetLastError(llRet);
    RaiseLastOSError;
  end;
end;

procedure TMyThread.DoTerminate;
begin
  if PMapData <> nil then UnmapViewOfFile(PMapData);
  if hMapping <> 0 then CloseHandle(hMapping);
  if hMapEvent <> 0 then CloseHandle(hMapEvent);
  if hMapLock <> 0 then CloseHandle(hMapLock);
  inherited;
end;