比如我用一个iocp控件,receive里面收到数据,写到一个内存池里面去
此内存池是否可以取出里面的块数据????安全吗?
unit MemoryPool;
interface
uses Windows, Classes, SysUtils;
const
BUFFER_SIZE = 4096; //接收缓冲区大小
DEFAULTBLOCKCOUNT = 4096;
//默认开4096个内存块 ,假设同时32个客户端,发送128个块(128 * 4096=524288字节)
type
EMemoryPool = class(Exception);
//TMemoryPool = class;
//实际将用到的内存块,可以扫描,找出相同文件的块,然后组成文件,减少数据库交互
PBlock = ^TBlock;
TBlock = packed record //相当于一个PBLOCK开辟的内存块=4096+n个字节
FileId:string[20];//文件ID 4区域Id + 2客户ID + 8日期 + 6序列号,每日可传输100万个文件,此信息在Data里面又包含有
Data: array[0..BUFFER_SIZE - 1] of Byte;
IsUse: Boolean;
//需要增加读写锁?因为需要扫描其他块,并合并,如果去读,而
//其他线程需要写怎么办,如果某线程正在写,又需要读,会不会读错误
end;
//内存池类
TMemoryPool = class
private
FList: TList;
FLock: TRTLCriticalSection;
function FGetCount: Integer; //取得内存池块数量
function FGetBlock(const Index: Integer): PBlock; //取得某块
protected
property Count: Integer read FGetCount; //块数量
property Blocks[const Index: Integer]: PBlock read FGetBlock; //取得某块
public
constructor Create(); overload;//初始化,默认块数
constructor Create(BlockCount: Integer); overload;//指定块数初始化
destructor Destroy; override;//释放
function AllocBlock: PBlock; //获得一个可用块
procedure RemoveBlock(Block: PBlock);//释放一个块
//自己扩展的
function GetCount: Integer; //取得内存池块数量
function GetBlock(const Index: Integer): PBlock; //取得某块
//published//改为开放的属性
// property Count: Integer read GetCount; //块数量
// property Blocks[const Index: Integer]: PBlock read GetBlock; //取得某块
end;
const
BLOCKSIZE: Word = SizeOf(TBlock);
implementation
//创建默认大小池
constructor TMemoryPool.Create();
begin
Create(DEFAULTBLOCKCOUNT);
end;
//创建指定大小池
constructor TMemoryPool.Create(BlockCount: Integer);
var
I: Integer;
P: PBlock;
begin
inherited Create;
InitializeCriticalSection(FLock);
FList := TList.Create;
for I := 0 to BlockCount - 1 do
begin
New(P);
FillChar(P^, BLOCKSIZE, 0);
FList.Add(P);
end;
end;
//释放池对象
destructor TMemoryPool.Destroy;
var
I: Integer;
begin
try
EnterCriticalSection(FLock);
for I := FList.Count - 1 downto 0 do
FreeMem(FList);
FList.Free;
finally
LeaveCriticalSection(FLock);
DeleteCriticalSection(FLock);
end;
inherited Destroy;
end;
//获取一个可用块
function TMemoryPool.AllocBlock: PBlock;
var
I: Integer;
begin
EnterCriticalSection(FLock);//进入临界区
try
Result := nil;
for I := FList.Count - 1 downto 0 do
begin
Result := FList;
if not Result.IsUse then
break;//找到可用空闲块
end;
if not Assigned(Result) or Result.IsUse then//最后也没有找到或者被释放了
begin
New(Result);//申请新的块
FList.Add(Result);//加入到列表
end;
FillChar(Result^.Data, SizeOf(Result^.Data), 0);//清空为0
Result^.IsUse := True;//使用标志
finally
LeaveCriticalSection(FLock);//离开临界区
end;
end;
//回收内存块到内存池中,可以继续使用
procedure TMemoryPool.RemoveBlock(Block: PBlock);
begin
EnterCriticalSection(FLock);
try
Block.IsUse := False;//只设置不使用标志
finally
LeaveCriticalSection(FLock);
end;
end;
//获得块数量
function TMemoryPool.FGetCount: Integer;
begin
Result := FList.Count;
end;
//获得一个数据块的指针,没有临界区控制,可以用来读取数据,写入也是可以的
//如果下标超过界限,保错误
function TMemoryPool.FGetBlock(const Index: Integer): PBlock;
begin
if (Index >= Count) or (Index <= -1) then
raise EMemoryPool.CreateFmt('需要不正确', [Index])
else
Result := FList[Index];
end;
//获得块数量
//加入临界区保护
function TMemoryPool.GetCount: Integer;
begin
EnterCriticalSection(FLock);
try
Result := FGetCount;
finally
LeaveCriticalSection(FLock);
end;
end;
//获得一个数据块的指针,没有临界区控制,可以用来读取数据,写入也是可以的
//如果下标超过界限,保错误
//加入临界区保护,因为 获得此 块指针 是线程安全的,所以读写也是?????
//*********************************************************************
//????????????????????????????????????????????????????????????????这个获得的
//指针读写是否安全???? 打算将tcp 收到的数据进行组包,扫描此内存池
function TMemoryPool.GetBlock(const Index: Integer): PBlock;
begin
EnterCriticalSection(FLock);
try
result := FGetBlock(Index);
finally
LeaveCriticalSection(FLock);
end;
end;
end.