在我基于Indy(TIdHTTPServer)的Web服务器应用程序中,每个HTTP会话都有一个单独的TDataModule,它将“按需”创建:
procedure TExampleHTTPServer.OnHandleRequest(Request:
TIdHTTPRequestInfo; Response: TIdHTTPResponseInfo);
const
KEY = 'datamodule';
var
Pos: Integer;
DM: TDemoDataModule;
Tmp: string;
S: string;
begin
Request.Session.Lock;
try
Pos := Request.Session.Content.IndexOf(KEY);
if Pos <> -1 then
begin
DM := TDemoDataModule(Request.Session.Content.Objects[Pos]);
end
else
begin
WriteLn(Format('Create datamodule for session %s',
[Request.Session.SessionID]));
DM := TDemoDataModule.Create(nil);
Request.Session.Content.AddObject(KEY, DM);
end;
finally
Request.Session.Unlock;
end;
... // do something with the datamodule - this is the interesting part
因此,无论何时从同一客户端HTTP会话发送请求,服务器都会尝试在会话对象中查找数据模块并使用它(存储会话特定数据,执行数据库查询等)。如果还没有数据模块实例,则服务器会创建它。
这有效,但是存在并发访问的风险:因为会话由会话令牌(存储在cookie中)标识,所以同一客户端可能同时使用相同的会话令牌打开两个连接,因此服务器将收到两个想要访问同一数据模块的请求。
因此,需要对数据模块实例进行线程安全访问。
我想最简单的解决方案是TMonitor,因此每次访问数据模块都会被包装:
TMonitor.Enter(DM);
try
DM.SomeProperty := AValue;
...
finally
TMonitor.Exit(DM);
end;
或者我错过了其他一些,也许更优雅的解决方案?