多进程共享内存的MemoryStream

文章转载于http://www.raysoftware.cn/?p=506

具体用处呢,有很多,比如多进程浏览器共享Cookie啦,多个进程传送点数据啦.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
共享内存封装.
封装成了MemoryStream的形式.
用法如下:
  var
    ms : TShareMemStream;
  ms := TShareMemStream.Create('Global\test', FILE_MAP_ALL_ACCESS, 4096);
  if (ms.Memory <> nil)(*and(ms.AlreadyExists)*) then
  //如果创建失败Memory指针是空指针
  //AlreadyExists表示已经存在了,也就是之前被别人(也许是别的进程)创建过了.
  begin
    //获取锁,多个进程线程访问安全访问
    if ms.GetLock(INFINITE) then
    begin
      ms.read(...);
      ms.write(...);
      //释放锁
      ms.ReleaseLock();
    end;
  end;
  ms.free;

 

共享类原文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
unit ShareMemoryStream;
  
interface
  
uses
  SysUtils, Classes, Syncobjs,
  Windows;
  
type
  TShareMemStream = class(TCustomMemoryStream)
  private
    FFile: THandle;
    FSize: Int64;
    FEvent: TEvent;
    FAlreadyExists: Boolean;
  protected
    property Event: TEvent read FEvent;
  public
    constructor Create(const ShareName: string;
      ACCESS: DWORD = FILE_MAP_ALL_ACCESS; ASize: Int64 = 16 * 1024 * 1024);
    destructor Destroy; override;
  
    function Write(const Buffer; Count: Integer): Longint; override;
  
    function GetLock(ATimeOut: DWORD = INFINITE): Boolean;
    procedure ReleaseLock();
  
    property AlreadyExists: Boolean read FAlreadyExists;
  end;
  
implementation
  
procedure InitSecAttr(var sa: TSecurityAttributes; var sd: TSecurityDescriptor);
begin
  sa.nLength := sizeOf(sa);
  sa.lpSecurityDescriptor := @sd;
  sa.bInheritHandle := false;
  InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@sd, true, nil, false);
end;
  
{ TShareMem }
  
constructor TShareMemStream.Create(const ShareName: string; ACCESS: DWORD;
  ASize: Int64);
var
  sa: TSecurityAttributes;
  sd: TSecurityDescriptor;
  lprotect: DWORD;
  e: Integer;
begin
  FEvent := TEvent.Create(nil, false, true, ShareName +
    '_TShareMemStream_Event');
  FSize := ASize;
  InitSecAttr(sa, sd);
  
  ACCESS := ACCESS and (not SECTION_MAP_EXECUTE);
  
  if (ACCESS and FILE_MAP_WRITE) = FILE_MAP_WRITE then
    lprotect := PAGE_READWRITE
  else if (ACCESS and FILE_MAP_READ) = FILE_MAP_READ then
    lprotect := PAGE_READONLY;
  
  FFile := CreateFileMapping(INVALID_HANDLE_VALUE, @sa, lprotect,
    Int64Rec(FSize).Hi, Int64Rec(FSize).Lo, PChar(ShareName));
  e := GetLastError;
  if FFile = 0 then
    Exit;
  FAlreadyExists := e = ERROR_ALREADY_EXISTS;
  SetPointer(MapViewOfFile(FFile, ACCESS, 0, 0, Int64Rec(FSize).Lo),
    Int64Rec(FSize).Lo);
end;
  
destructor TShareMemStream.Destroy;
begin
  if Memory <> nil then
  begin
    UnmapViewOfFile(Memory);
    SetPointer(nil, 0);
    Position := 0;
  end;
  if FFile <> 0 then
  begin
    CloseHandle(FFile);
    FFile := 0;
  end;
  FEvent.Free;
  inherited Destroy;
end;
  
function TShareMemStream.GetLock(ATimeOut: DWORD): Boolean;
var
  wr : TWaitResult;
begin
  wr := FEvent.WaitFor(ATimeOut);
  Result := wr = wrSignaled;
end;
  
procedure TShareMemStream.ReleaseLock;
begin
  FEvent.SetEvent;
end;
  
function TShareMemStream.Write(const Buffer; Count: Integer): Longint;
begin
  Result := 0;
  if (Size - Position) >= Count then
  begin
    System.Move(Buffer, PByte(Memory)[Position], Count);
    Position := Position + Count;
    Result := Count;
  end;
end;
  
end.

  

posted @   _成飞  阅读(496)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示