Top.Mail.Ru
Ответы

Delphi, TThread: CriticalSection и Synchronize

Добрый день. Только полез в потоки разбираться, не пойму как правильно работать с этими методами.
Вот текст (выборочно):

type
TCalcThread = class(TThread)
private
LaDB: TFIBDatabase;
LaTRN: TFIBTransaction;
protected
procedure Execute; override;
public
procedure ConstructPriv(IDRes, IDPer, IDTarif, IDReason: Integer);
var
SBDisplayString: String;
end;

implementation

procedure TCalcThread.Execute;
var TC : TCalcParams;
CalcRes: TPair<tcalcparams,integer>;
D: TpFIBDataSet;
label WaitCycle, CalcCycle;
begin
inherited;

CriticalSection.Enter;
SBDisplayString := 'Запуск расчетного модуля';
Synchronize(MainForm.ShowCalcGUI);
...
CriticalSection.Leave;
SBDisplayString := '';
Synchronize(MainForm.ShowCalcGUI);
...

end;

procedure TCalcThread.ConstructPriv(IDRes, IDPer, IDTarif, IDReason: Integer);
var D: TFIBDataSet; TC : TCalcParams;
begin
//
try
CriticalSection.Enter;
SBDisplayString := 'Обновление списка';
Synchronize(MainForm.ShowCalcGUI);
CriticalSection.Leave;
...
finally
FreeAndNil(D);
SBDisplayString := '';
Synchronize(MainForm.ShowCalcGUI);
end;
end;

Смысл такой, что ConstructPriv должна выполнять не особо быстрые запросы к базе FB, и строить некоторый список-очередь обработки (это от 0 до 5 секунд может занимать). А сам поток этот список потом обрабатывать (тут и до нескольких минут идут расчеты). В Execute в критической секции в начале идет подключение к БД.

Запускается поток так:
if TheCalcThread.Suspended then TheCalcThread.Start;
...тут буквально 2-3 оператора
TheCalcThread.ConstructPriv(IDRes, IDPer, IDTrans, IDReason);

В таком виде при запуске построения списка программа виснет. Если Synchronize вынести за секцию, то не виснет. Или если запуск производить Судя по точкам остановок, похоже что программа запускает синхронизацию и сразу же идет выполнение процедуры списка, и на первом операторе - входе в секцию, виснет. Не могли бы пояснить, кто четко представляет, как именно происходит все это, что приостанавливается, что нет, в критических секциях и синхронизациях?
Спасибо

По дате
По рейтингу
Аватар пользователя
Просветленный
11лет

>> TheCalcThread.ConstructPriv(IDRes, IDPer, IDTrans, IDReason);
имхо, это плохая практика вызывать методы класса потока из другого потока. Лучше использование потока ограничить только вызовом методом Execute. А если нужно изменить поведение выполнения потока, тогда лучше в классе потока завести какие-нибудь флаги, а в методе Execute проверять установлен флаг или нет.

На счет зависания, ты из главного потока вызываешь TheCalcThread.ConstructPriv, и скорее всего доступ к этой секции все еще залочен той-же секцией в TCalcThread.Execute. Попробуй завести для каждого участка кода разные крит. секции.