如何保护绑定到HTTP会话的TDataModule免受并发使用的影响?

时间:2016-01-11 12:07:51

标签: delphi http concurrency indy

在我基于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;

或者我错过了其他一些,也许更优雅的解决方案?

0 个答案:

没有答案