unit Main;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TMainForm = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private{ Private declarations }public{ Public declarations }end;
var
MainForm: TMainForm;
implementation{$R *.DFM}{ NOTE: Change GlobalStr from var to threadvar to see difference }var//threadvar
GlobalStr: string;
type
TTLSThread = class(TThread)
private
FNewStr: string;
protectedprocedure Execute; override;
publicconstructor Create(const ANewStr: string);
end;
procedure SetShowStr(const S: string);
beginif S = '' then
MessageBox(0, PChar(GlobalStr), 'The string is...', MB_OK)
else
GlobalStr := S;
end;
constructor TTLSThread.Create(const ANewStr: string);
begin
FNewStr := ANewStr;
inherited Create(False);
end;
procedure TTLSThread.Execute;
begin
FreeOnTerminate := True;
SetShowStr(FNewStr);
SetShowStr('');
end;
procedure TMainForm.Button1Click(Sender: TObject);
begin
SetShowStr('Hello world');
SetShowStr('');
TTLSThread.Create('Dilbert');
Sleep(100);
SetShowStr('');
end;
end.
Программа на Delphi, демонстрирующая использование глобальной переменной в многопоточной среде.
Программа состоит из двух основных компонентов: формы с кнопкой и класса потока TTLSThread.
Когда кнопка на форме кликается, она вызывает процедуру SetShowStr с строкой "Hello world". Это устанавливает значение глобальной переменной GlobalStr. Затем она создает экземпляр класса TTLSThread с параметром строкой "Dilbert".
Поток выполняется в отдельном потоке и сначала устанавливает глобальную переменную в строку "Dilbert", а затем возвращает ее в пустую строку. Затем программа спит на 100 миллисекунд перед тем, как установить глобальную переменную в пустую строку снова.
Вот некоторые вещи, которые стоит отметить:
Глобальная переменная GlobalStr объявлена как обычная переменная, а не как локальная переменная потока (threadvar). Это означает, что все потоки будут доступаться и модифицировать ту же глобальную переменную.
Программа использует функцию Sleep для приостановки выполнения основного потока на 100 миллисекунд. Это используется для демонстрации эффекта, когда поток модифицирует глобальную переменную.
Чтобы увидеть разницу между использованием обычной переменной и локальной переменной потока, можно uncomment строку //threadvar перед объявлением GlobalStr. Это объявит GlobalStr как локальную переменную потока, что означает, что каждый поток будет иметь свой отдельный экземпляр переменной. В этом случае основной поток не увидит изменения, сделанные потоком.
В целом, программа демонстрирует использование глобальных переменных в многопоточной среде и создание и управление потоками в Delphi.
Вот некоторые предложения по улучшению:
вместо использования Sleep для приостановки выполнения основного потока можно использовать синхронизационные примитивы, такие как семафоры или события, для координации между потоками.
можно добавить более надежное обслуживание ошибок и журналирование, чтобы обеспечить корректное поведение программы в случае ошибок или исключений.
можно рассмотреть использование более сложной модели потока, такой как пул рабочих потоков, для управления множеством задач.concurrently.
Вот обновленная версия кода с некоторыми улучшениями:
unitMain;interfaceusesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls;typeTMainForm=class(TForm)Button1:TButton;procedureButton1Click(Sender:TObject);private{ Private declarations }public{ Public declarations }end;varMainForm:TMainForm;implementation{$R *.DFM}{ NOTE: Change GlobalStr from var to threadvar to see difference }var//threadvarGlobalStr:string;typeTTLSThread=class(TThread)privateFNewStr:string;protectedprocedureExecute;override;publicconstructorCreate(constANewStr:string);end;procedureSetShowStr(constS:string);beginifS=''thenMessageBox(0,PChar(GlobalStr),'The string is...',MB_OK)elseGlobalStr:=S;end;constructorTTLSThread.Create(constANewStr:string);beginFNewStr:=ANewStr;inheritedCreate(False);end;procedureTTLSThread.Execute;beginFreeOnTerminate:=True;SetShowStr(FNewStr);SetShowStr('');end;procedureTMainForm.Button1Click(Sender:TObject);beginSetShowStr('Hello world');SetShowStr('');TTLSThread.Create('Dilbert');SyncProc;// Wait for the thread to finishSetShowStr('');end;end.
Я добавил вызов SyncProc после создания потока, который обеспечивает, что основной поток ждет, пока поток не закончит выполнение, прежде чем продолжать. Это предотвращает программу от попытки доступа к глобальной переменной, когда она модифицируется другим потоком.
В статье описывается пример использования потока с доступом к глобальной переменной основной программы в языке Delphi, где создается отдельный поток для выполнения задачи и изменяет значение глобальной переменной.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS