Я экспериментирую с многопоточностью в Delphi (XE) и столкнулся с проблемой с использованием глобальной переменной между основным потоком VCL и вторым рабочим потоком.
В моем проекте задействован второй рабочий поток, который просматривает некоторые файлы и обновляет строку globalvar с текущим именем файла. Затем эта глобальная переменная выбирается таймером в основном потоке VCL и обновляет строку состояния.
Я заметил, что иногда возникает ошибка «Недопустимая операция указателя» ... или «Недостаточно памяти», или рабочий поток просто перестает отвечать (возможно, тупик).
Поэтому я создал тестовое приложение для выявления и значительного увеличения вероятности ошибки, чтобы я мог видеть, что происходит.
type
TSyncThread = class(TThread)
protected
procedure Execute; override;
end;
var
Form11: TForm11;
ProgressString : String;
ProgressCount : Int64;
SyncThread : TSyncThread;
CritSect : TRTLCriticalSection;
implementation
{$R *.dfm}
procedure TForm11.StartButtonClick(Sender: TObject);
begin
Timer1.Enabled := true;
SyncThread := TSyncThread.Create(True);
SyncThread.Start;
end;
procedure TForm11.StopbuttonClick(Sender: TObject);
begin
Timer1.Enabled := false;
SyncThread.Terminate;
end;
procedure TForm11.Timer1Timer(Sender: TObject);
begin
StatusBar1.Panels[0].Text := 'Count: ' + IntToStr(ProgressCount);
StatusBar1.Panels[1].Text := ProgressString;
end;
procedure TSyncThread.Execute;
var
i : Int64;
begin
i := 0;
while not Terminated do begin
inc(i);
EnterCriticalSection(CritSect);
ProgressString := IntToStr(i);
ProgressCount := i;
LeaveCriticalSection(CritSect);
end;
end;
initialization
InitializeCriticalSection(CritSect);
finalization
DeleteCriticalSection(CritSect);
Я установил интервал таймера на 10 мс, чтобы он много читал, в то время как рабочий поток постоянно обновлял глобальную строку var. Конечно, при запуске этого приложения не хватает секунды, прежде чем возникают указанные выше ошибки.
У меня вопрос: нужно ли выполнять операцию чтения глобальной переменной в таймере VCL в критическом разделе? - если да, то почему ?. Насколько я понимаю, это только чтение, и, поскольку записи уже выполняются в критическом разделе, я не могу понять, почему это вызывает проблему. Если я все же помещаю показания таймера в критическую секцию - все работает нормально ....но я недоволен тем, что делаю это, не зная почему!
Я новичок в многопоточности, поэтому был бы признателен за любую помощь в объяснении, почему этот простой пример вызывает всевозможные проблемы, и есть ли лучший способ доступа к строке из рабочего потока.