Выборочный критический раздел - условный - PullRequest
0 голосов
/ 14 апреля 2011

У меня есть поток, который принимает таблицу БД в качестве параметра, у меня возникла проблема, когда я не могу одновременно записать в эту таблицу БД.

1 экземпляр TMyThread может иметь таблицу БД'Member', в то время как у другого может быть 'Staff', однако могут быть случаи, когда два потока открываются с одной и той же таблицей.

Таким образом, мне нужно обернуть код в критический раздел (или аналогичный), но я нене нужны какие-то грязные вещи, такие как несколько сечений, например (fMemberTable, fStaffTable) ...

begin
    if fDBTable = 'Member' then
        fMemberTable.Enter
    else if fDbTable = 'Staff' then
    ....

У нас есть 8 таблиц, которые могут стать грязными. Есть ли способ сделать

TCricalSection(fMemberTable) Введите желанную;Или какой-то способ сделать это, который легко «масштабировать» и использовать?

Один критический раздел вокруг функции не имеет смысла, так как я не хочу сдерживать другие таблицы ....

Ответы [ 2 ]

2 голосов
/ 14 апреля 2011

Вы можете сделать:

TMonitor.Enter(fMemberTable);
try
  // Do your stuff
finally TMonitor.Exit(fMemberTable);
end;

Обратите внимание, что это SPIN LOCK, а не настоящий критический раздел. Очень практично, если у вас не будет много коллизий, но если потоки регулярно блокируют друг друга, вы можете вернуться к критической секции. Спин-блокировка по определению является блокировкой ожидания ожидания.

но я не уверен, какая версия Delphi представила это, и у вас нет специфичных для версии тегов.

0 голосов
/ 15 апреля 2011

Вы можете использовать список критических разделов, например, Мой класс, определенный в этом модуле:

interface
uses Classes, SyncObjs;

type
  { TCriticalSectionList by jachguate }
  { http://jachguate.wordpress.com }
  TCriticalSectionList = class
  private
    FCSList: TThreadList;
    FNameList: TStringList;
    function GetByName(AName: string): TCriticalSection;
  public
    constructor Create();
    destructor Destroy(); override;
    property ByName[AName: string]: TCriticalSection read GetByName; default;
  end;

  function CSList: TCriticalSectionList;

implementation
uses SysUtils;

{ TCriticalSectionList }

constructor TCriticalSectionList.Create;
begin
  inherited;
  FCSList := TThreadList.Create;
  FNameList := TStringList.Create;
end;

destructor TCriticalSectionList.Destroy;
var
  I: Integer;
  AList: TList;
begin
  AList := FCSList.LockList;
  for I := AList.Count - 1 downto 0 do
    TCriticalSection(AList[I]).Free;
  FCSList.Free;
  FNameList.Free;
  inherited;
end;


function TCriticalSectionList.GetByName(AName: string): TCriticalSection;
var
  AList: TList;
  AIdx: Integer;
begin
  AList := FCSList.LockList;
  try
    AName := UpperCase(AName);
    AIdx := FNameList.IndexOf(AName);
    if AIdx < 0 then
    begin
      FNameList.Add(AName);
      Result := TCriticalSection.Create;
      AList.Add(Result);
    end
    else
      Result := AList[AIdx];
  finally
    FCSList.UnlockList;
  end;
end;

var
  _CSList: TCriticalSectionList;

function CSList: TCriticalSectionList;
begin
  if not Assigned(_CSList) then
    _CSList := TCriticalSectionList.Create;
  Result := _CSList;
end;

initialization
  _CSList := nil;
finalization
  _CSList.Free;
end.

Класс в основном определяет список критических разделов, доступный по «имени». Когда вы впервые запрашиваете критический раздел с определенным именем, этот критический раздел создается автоматически для вас. Вы должны получить доступ к одному экземпляру этого класса, используя предоставленную функцию CSList.

Все критические разделы уничтожаются при уничтожении экземпляра списка, например, экземпляр «по умолчанию» уничтожается по завершении приложения.

Вы можете написать код, как в этом примере:

begin
  CSList[fDBTable].Enter;
  try
    DoStuff;
  finally
    CSList[fDBTable].Leave;
  end;
end;

Наслаждайтесь.

...