mirror of
https://github.com/loginov-dmitry/multithread.git
synced 2024-11-28 09:33:03 +02:00
pas-файлы сохранены в кодировке UTF-8
This commit is contained in:
parent
271b6a0790
commit
98fdc4ed9f
@ -80,15 +80,6 @@ object Form1: TForm1
|
||||
ScrollBars = ssVertical
|
||||
TabOrder = 2
|
||||
end
|
||||
object Button1: TButton
|
||||
Left = 304
|
||||
Top = 168
|
||||
Width = 201
|
||||
Height = 25
|
||||
Caption = #1047#1072#1087#1091#1089#1090#1080#1090#1100' Sleep-'#1087#1086#1090#1086#1082
|
||||
TabOrder = 3
|
||||
OnClick = Button1Click
|
||||
end
|
||||
object Timer1: TTimer
|
||||
Interval = 500
|
||||
OnTimer = Timer1Timer
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit CalcTimeQuantUnit;
|
||||
unit CalcTimeQuantUnit;
|
||||
|
||||
interface
|
||||
|
||||
@ -9,29 +9,24 @@ uses
|
||||
type
|
||||
TCalcQuantThread = class(TThread)
|
||||
private
|
||||
// Добавляет длительность интервала активности (квант времени)
|
||||
// Добавляет длительность интервала активности (квант времени)
|
||||
procedure AddToWorkList(WorkTime: Double);
|
||||
|
||||
// Добавляет длительность интервала бездействия (в спящем состоянии)
|
||||
// Добавляет длительность интервала бездействия (в спящем состоянии)
|
||||
procedure AddToNotWorkList(NotWorkTime: Double);
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
ThreadNum: Integer; // Номер потока
|
||||
IsFinish: Boolean; // Флаг "работа потока завершена"
|
||||
WorkAll: Double; // Общее время работы
|
||||
NotWorkAll: Double; // Общее время бездействия
|
||||
LoopCount: Integer; // Количество циклов
|
||||
WorkList: array of Double; // Длительность выделенных квантов времени
|
||||
NotWorkList: array of Double; // Длительность интервалов простоя
|
||||
ThreadNum: Integer; // Номер потока
|
||||
IsFinish: Boolean; // Флаг "работа потока завершена"
|
||||
WorkAll: Double; // Общее время работы
|
||||
NotWorkAll: Double; // Общее время бездействия
|
||||
LoopCount: Integer; // Количество циклов
|
||||
WorkList: array of Double; // Длительность выделенных квантов времени
|
||||
NotWorkList: array of Double; // Длительность интервалов простоя
|
||||
constructor Create(ThreadNum: Integer);
|
||||
end;
|
||||
|
||||
TSleepThread = class(TThread)
|
||||
protected
|
||||
procedure Execute; override;
|
||||
end;
|
||||
|
||||
TForm1 = class(TForm)
|
||||
Label1: TLabel;
|
||||
Label2: TLabel;
|
||||
@ -40,16 +35,13 @@ type
|
||||
Label3: TLabel;
|
||||
Memo1: TMemo;
|
||||
Timer1: TTimer;
|
||||
Button1: TButton;
|
||||
procedure btnStartThreadsClick(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure Timer1Timer(Sender: TObject);
|
||||
procedure Button1Click(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FList: TList; // Список запущенных потоков
|
||||
SleepThread: TSleepThread;
|
||||
FList: TList; // Список запущенных потоков
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
@ -71,11 +63,6 @@ begin
|
||||
btnStartThreads.Enabled := False;
|
||||
end;
|
||||
|
||||
procedure TForm1.Button1Click(Sender: TObject);
|
||||
begin
|
||||
SleepThread := TSleepThread.Create(False);
|
||||
end;
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
begin
|
||||
FList := TList.Create;
|
||||
@ -103,13 +90,13 @@ begin
|
||||
T := TCalcQuantThread(FList[I]);
|
||||
if T.IsFinish then
|
||||
begin
|
||||
s := Format('Интервалы активности потока #%d (Общее время=%f; Число квантов=%d; '+
|
||||
'Число циклов=%d): ', [T.ThreadNum, T.WorkAll, Length(T.WorkList), T.LoopCount]);
|
||||
s := Format('Интервалы активности потока #%d (Общее время=%f; Число квантов=%d; '+
|
||||
'Число циклов=%d): ', [T.ThreadNum, T.WorkAll, Length(T.WorkList), T.LoopCount]);
|
||||
for Q in T.WorkList do
|
||||
s := s + FormatFloat('0.0000', Q) + ',';
|
||||
Memo1.Lines.Add(s);
|
||||
s := Format('Интервалы бездействия потока #%d (Общее время=%f; Число интервалов '+
|
||||
'бездействия=%d): ', [T.ThreadNum, T.NotWorkAll, Length(T.NotWorkList)]);
|
||||
s := Format('Интервалы бездействия потока #%d (Общее время=%f; Число интервалов '+
|
||||
'бездействия=%d): ', [T.ThreadNum, T.NotWorkAll, Length(T.NotWorkList)]);
|
||||
for Q in T.NotWorkList do
|
||||
s := s + FormatFloat('0.0000', Q) + ',';
|
||||
Memo1.Lines.Add(s + sLineBreak);
|
||||
@ -161,26 +148,19 @@ begin
|
||||
QueryPerformanceCounter(CurTicks);
|
||||
Inc(LoopCount);
|
||||
if CurTicks - PrevTicks > QuantDiff then
|
||||
begin // Если разница оказалась больше 1 мс, значит ОС приостанавливала
|
||||
// работу потока и теперь начался отсчёт нового кванта
|
||||
AddToWorkList(CurQuantTime / Freq); // Сохраняем время работы потока
|
||||
AddToNotWorkList((CurTicks - PrevTicks) / Freq); // Сохраняем время простоя потока
|
||||
begin // Если разница оказалась больше 1 мс, значит ОС приостанавливала
|
||||
// работу потока и теперь начался отсчёт нового кванта
|
||||
AddToWorkList(CurQuantTime / Freq); // Сохраняем время работы потока
|
||||
AddToNotWorkList((CurTicks - PrevTicks) / Freq); // Сохраняем время простоя потока
|
||||
CurQuantStart := CurTicks;
|
||||
CurQuantTime := 0;
|
||||
end else
|
||||
CurQuantTime := CurTicks - CurQuantStart;
|
||||
PrevTicks := CurTicks;
|
||||
until (CurTicks - StartTicks) > BreakDiff;
|
||||
if CurQuantTime > 0 then // Обрабатываем длительность последнего кванта
|
||||
if CurQuantTime > 0 then // Обрабатываем длительность последнего кванта
|
||||
AddToWorkList(CurQuantTime / Freq);
|
||||
IsFinish := True;
|
||||
end;
|
||||
|
||||
{ TSleepThread }
|
||||
|
||||
procedure TSleepThread.Execute;
|
||||
begin
|
||||
while not Terminated do Sleep(1);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
Copyright (c) 2020, Loginov Dmitry Sergeevich
|
||||
All rights reserved.
|
||||
|
||||
@ -34,14 +34,13 @@ uses
|
||||
type
|
||||
TThreadAccessTerminated = class(TThread);
|
||||
|
||||
// Подсказка самому себе, где находится TObjectList
|
||||
// Подсказка самому себе, где находится TObjectList
|
||||
TObjectListHelp = class(Contnrs.TObjectList);
|
||||
|
||||
|
||||
// Простой пример организации паузы в работе потока с контролем свойства Terminate
|
||||
// Простой пример организации паузы в работе потока с контролем свойства Terminate
|
||||
procedure ThreadWaitTimeout(AThread: TThread; ATimeout: Integer);
|
||||
|
||||
// Эмуляция полезной работы
|
||||
// Эмуляция полезной работы
|
||||
procedure EmulateUsefullWork(WorkTime: Integer);
|
||||
|
||||
procedure ThreadShowMessageFmt(Msg: string; Args: array of const);
|
||||
@ -68,61 +67,61 @@ begin
|
||||
Sleep(WorkTime);
|
||||
end;
|
||||
|
||||
// Реализация, основанная на функции GetTickCount
|
||||
// Реализация, основанная на функции GetTickCount
|
||||
{procedure ThreadWaitTimeout(AThread: TThread; ATimeout: Integer);
|
||||
var
|
||||
StartTime, Diff, tc: Cardinal;
|
||||
T: TThreadAccessTerminated;
|
||||
begin
|
||||
// Получаем доступ к protected-свойству Terminated
|
||||
// Получаем доступ к protected-свойству Terminated
|
||||
T := TThreadAccessTerminated(AThread);
|
||||
// Если поток нужно завершить, то сразу выходим из цикла
|
||||
// Если поток нужно завершить, то сразу выходим из цикла
|
||||
if T.Terminated then Exit;
|
||||
|
||||
// Запоминаем текущее время (в миллисекундах от включения компьютера)
|
||||
// Запоминаем текущее время (в миллисекундах от включения компьютера)
|
||||
StartTime := GetTickCount;
|
||||
while True do
|
||||
begin
|
||||
tc := GetTickCount;
|
||||
|
||||
// Прерываем ожидание, если функция GetTickCount начала новый круг
|
||||
// иначе наша функция ожидания может зависнуть
|
||||
// Прерываем ожидание, если функция GetTickCount начала новый круг
|
||||
// иначе наша функция ожидания может зависнуть
|
||||
if (tc < StartTime) then Exit;
|
||||
|
||||
// Прерываем ожидание, если превысили указанный таймаут
|
||||
// Прерываем ожидание, если превысили указанный таймаут
|
||||
Diff := tc - StartTime;
|
||||
if (Diff >= ATimeout) or T.Terminated then
|
||||
Exit;
|
||||
|
||||
// Замораживаем поток примерно на 20 мс
|
||||
// Замораживаем поток примерно на 20 мс
|
||||
Sleep(20);
|
||||
end;
|
||||
end; }
|
||||
|
||||
// Реализация, основанная на TPerformance
|
||||
// Реализация, основанная на TPerformance
|
||||
procedure ThreadWaitTimeout(AThread: TThread; ATimeout: Integer);
|
||||
var
|
||||
p: TTimeInterval;
|
||||
T: TThreadAccessTerminated;
|
||||
begin
|
||||
// Получаем доступ к protected-свойству Terminated
|
||||
// Получаем доступ к protected-свойству Terminated
|
||||
T := TThreadAccessTerminated(AThread);
|
||||
// Если поток нужно завершить, то сразу выходим из цикла
|
||||
// Если поток нужно завершить, то сразу выходим из цикла
|
||||
if T.Terminated then Exit;
|
||||
|
||||
p.Start; // Начинаем замер времени
|
||||
p.Start; // Начинаем замер времени
|
||||
while True do
|
||||
begin
|
||||
if T.Terminated or (p.ElapsedMilliseconds >= ATimeout) then
|
||||
Exit;
|
||||
// Замораживаем поток примерно на 20 мс
|
||||
// Замораживаем поток примерно на 20 мс
|
||||
Sleep(ThreadWaitTimeoutSleepTime);
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
// Критическая секция для защиты строк от
|
||||
// одновременного доступа из разных потоков
|
||||
// Критическая секция для защиты строк от
|
||||
// одновременного доступа из разных потоков
|
||||
StringProtectSection := TCriticalSection.Create;
|
||||
|
||||
finalization
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex1Unit;
|
||||
unit Ex1Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -35,7 +35,7 @@ var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
// Очень длинный цикл. Имитирует длительные вычисления.
|
||||
// Очень длинный цикл. Имитирует длительные вычисления.
|
||||
for I := 1 to MaxInt do
|
||||
Result := Result + Random(1000);
|
||||
end;
|
||||
@ -47,7 +47,7 @@ end;
|
||||
|
||||
procedure TForm1.btnRunInParallelThreadClick(Sender: TObject);
|
||||
begin
|
||||
// Запускает параллельный поток
|
||||
// Запускает параллельный поток
|
||||
TMyThread.Create(False);
|
||||
end;
|
||||
|
||||
@ -59,7 +59,7 @@ var
|
||||
begin
|
||||
FreeOnTerminate := True;
|
||||
V := DoLongCalculations;
|
||||
MyShowMessage('Результат: ' + IntToStr(V));
|
||||
MyShowMessage('Результат: ' + IntToStr(V));
|
||||
end;
|
||||
|
||||
procedure TForm1.btnRunInMainThreadClick(Sender: TObject);
|
||||
@ -67,7 +67,7 @@ var
|
||||
V: Int64;
|
||||
begin
|
||||
V := DoLongCalculations;
|
||||
MyShowMessage('Результат: ' + IntToStr(V));
|
||||
MyShowMessage('Результат: ' + IntToStr(V));
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex2Unit;
|
||||
unit Ex2Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -9,7 +9,7 @@ uses
|
||||
type
|
||||
TMyLongThread = class(TThread)
|
||||
private
|
||||
procedure DoUsefullTask; // Процедура для имитации полезной работы
|
||||
procedure DoUsefullTask; // Процедура для имитации полезной работы
|
||||
public
|
||||
procedure Execute; override;
|
||||
end;
|
||||
@ -34,20 +34,20 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunParallelThreadClick(Sender: TObject);
|
||||
begin
|
||||
// Запускает параллельный поток
|
||||
// Запускает параллельный поток
|
||||
if MyThread = nil then
|
||||
MyThread := TMyLongThread.Create(False)
|
||||
else
|
||||
raise Exception.Create('Дополнительный поток уже запущен!');
|
||||
raise Exception.Create('Дополнительный поток уже запущен!');
|
||||
end;
|
||||
|
||||
{ TMyLongThread }
|
||||
|
||||
procedure TMyLongThread.DoUsefullTask;
|
||||
begin
|
||||
// Реальный поток может выполнять какую угодно полезную работу
|
||||
// В учебных целях делаем паузу 5 секунд для имитации задержки, которая
|
||||
// может возникнуть при выполнении полезной работы
|
||||
// Реальный поток может выполнять какую угодно полезную работу
|
||||
// В учебных целях делаем паузу 5 секунд для имитации задержки, которая
|
||||
// может возникнуть при выполнении полезной работы
|
||||
Sleep(5000);
|
||||
end;
|
||||
|
||||
@ -60,14 +60,14 @@ begin
|
||||
while not Terminated do
|
||||
begin
|
||||
DoUsefullTask;
|
||||
WaitTimeout(10000); // Ожидаем таймаут 10 сек.
|
||||
WaitTimeout(10000); // Ожидаем таймаут 10 сек.
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
// При закрытии программы необходимо завершить работу потока
|
||||
// и уничтожить объект потока MyThread
|
||||
// При закрытии программы необходимо завершить работу потока
|
||||
// и уничтожить объект потока MyThread
|
||||
if MyThread <> nil then
|
||||
MyThread.Free;
|
||||
end;
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex3Unit;
|
||||
unit Ex3Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -9,7 +9,7 @@ uses
|
||||
type
|
||||
TMyShortThread = class(TThread)
|
||||
private
|
||||
procedure DoUsefullTask; // Процедура для имитации полезной работы
|
||||
procedure DoUsefullTask; // Процедура для имитации полезной работы
|
||||
public
|
||||
procedure Execute; override;
|
||||
end;
|
||||
@ -34,8 +34,8 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunParallelThreadClick(Sender: TObject);
|
||||
begin
|
||||
// Запускает параллельный поток. Если объект потока уже создан,
|
||||
// то уничтожает его.
|
||||
// Запускает параллельный поток. Если объект потока уже создан,
|
||||
// то уничтожает его.
|
||||
if MyThread <> nil then
|
||||
FreeAndNil(MyThread);
|
||||
MyThread := TMyShortThread.Create(False);
|
||||
@ -47,10 +47,10 @@ procedure TMyShortThread.DoUsefullTask;
|
||||
var
|
||||
AProgress: TProgressViewer;
|
||||
begin
|
||||
// Реальный поток может выполнять какую угодно полезную работу
|
||||
// В учебных целях делаем паузу 5 секунд для имитации задержки, которая
|
||||
// может возникнуть при выполнении полезной работы
|
||||
AProgress := TProgressViewer.Create('Выполняется поток TMyShortThread');
|
||||
// Реальный поток может выполнять какую угодно полезную работу
|
||||
// В учебных целях делаем паузу 5 секунд для имитации задержки, которая
|
||||
// может возникнуть при выполнении полезной работы
|
||||
AProgress := TProgressViewer.Create('Выполняется поток TMyShortThread');
|
||||
Sleep(5000);
|
||||
AProgress.TerminateProgress;
|
||||
end;
|
||||
@ -62,8 +62,8 @@ end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
// При закрытии программы необходимо завершить работу потока
|
||||
// и уничтожить объект потока MyThread
|
||||
// При закрытии программы необходимо завершить работу потока
|
||||
// и уничтожить объект потока MyThread
|
||||
if MyThread <> nil then
|
||||
MyThread.Free;
|
||||
end;
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex4Unit;
|
||||
unit Ex4Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -10,9 +10,9 @@ type
|
||||
TMyLongThread = class(TThread)
|
||||
private
|
||||
FTaskNum: Integer;
|
||||
procedure DoUsefullTask1; // Первая задача
|
||||
procedure DoUsefullTask2; // Вторая задача
|
||||
procedure DoFinalizeTask; // Задача запускается при завершении работы потока
|
||||
procedure DoUsefullTask1; // Первая задача
|
||||
procedure DoUsefullTask2; // Вторая задача
|
||||
procedure DoFinalizeTask; // Задача запускается при завершении работы потока
|
||||
public
|
||||
constructor Create(TaskNum: Integer);
|
||||
procedure Execute; override;
|
||||
@ -26,8 +26,8 @@ type
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
MyThread1: TMyLongThread; // Поток для первой задачи
|
||||
MyThread2: TMyLongThread; // Поток для второй задачи
|
||||
MyThread1: TMyLongThread; // Поток для первой задачи
|
||||
MyThread2: TMyLongThread; // Поток для второй задачи
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
@ -41,11 +41,11 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunParallelThreadsClick(Sender: TObject);
|
||||
begin
|
||||
// Запускает параллельный поток для задачи 1
|
||||
// Запускает параллельный поток для задачи 1
|
||||
if MyThread1 = nil then
|
||||
MyThread1 := TMyLongThread.Create(1);
|
||||
|
||||
// Запускает параллельный поток для задачи 2
|
||||
// Запускает параллельный поток для задачи 2
|
||||
if MyThread2 = nil then
|
||||
MyThread2 := TMyLongThread.Create(2);
|
||||
end;
|
||||
@ -54,25 +54,25 @@ end;
|
||||
|
||||
constructor TMyLongThread.Create(TaskNum: Integer);
|
||||
begin
|
||||
inherited Create(False); // Вызываем родительский конструктор
|
||||
inherited Create(False); // Вызываем родительский конструктор
|
||||
|
||||
// Запоминаем параметр TaskNum. Он нужен в методе Execute
|
||||
// Запоминаем параметр TaskNum. Он нужен в методе Execute
|
||||
FTaskNum := TaskNum;
|
||||
end;
|
||||
|
||||
procedure TMyLongThread.DoFinalizeTask;
|
||||
begin
|
||||
Sleep(5000); // Данная условная задача занимает 5 секунд
|
||||
Sleep(5000); // Данная условная задача занимает 5 секунд
|
||||
end;
|
||||
|
||||
procedure TMyLongThread.DoUsefullTask1;
|
||||
begin
|
||||
Sleep(1000); // Данная условная задача занимает 1 секунду
|
||||
Sleep(1000); // Данная условная задача занимает 1 секунду
|
||||
end;
|
||||
|
||||
procedure TMyLongThread.DoUsefullTask2;
|
||||
begin
|
||||
Sleep(2000); // Данная условная задача занимает 2 секунды
|
||||
Sleep(2000); // Данная условная задача занимает 2 секунды
|
||||
end;
|
||||
|
||||
procedure TMyLongThread.Execute;
|
||||
@ -85,17 +85,17 @@ begin
|
||||
begin
|
||||
if Terminated then
|
||||
begin
|
||||
DoFinalizeTask; // Некоторые действия при завершении потока
|
||||
Exit; // Завершаем работу потока
|
||||
DoFinalizeTask; // Некоторые действия при завершении потока
|
||||
Exit; // Завершаем работу потока
|
||||
end else
|
||||
begin
|
||||
if FTaskNum = 1 then
|
||||
DoUsefullTask1 // Запускаем задачу 1
|
||||
DoUsefullTask1 // Запускаем задачу 1
|
||||
else
|
||||
DoUsefullTask2; // Запускаем задачу 2
|
||||
DoUsefullTask2; // Запускаем задачу 2
|
||||
|
||||
if not Terminated then // Дополнительная проверка не повредит!
|
||||
WaitTimeout(1000); // Ожидаем таймаут 1 сек
|
||||
if not Terminated then // Дополнительная проверка не повредит!
|
||||
WaitTimeout(1000); // Ожидаем таймаут 1 сек
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -104,14 +104,14 @@ procedure TForm1.FormDestroy(Sender: TObject);
|
||||
var
|
||||
AProgress: TProgressViewer;
|
||||
begin
|
||||
AProgress := TProgressViewer.Create('Выход из программы');
|
||||
AProgress := TProgressViewer.Create('Выход из программы');
|
||||
try
|
||||
if cbTerminateMode.ItemIndex = 1 then
|
||||
begin // Выбран режим "Одновременно (быстрее)"
|
||||
begin // Выбран режим "Одновременно (быстрее)"
|
||||
if Assigned(MyThread1) then
|
||||
MyThread1.Terminate; // Выставляем флаг Terminated
|
||||
MyThread1.Terminate; // Выставляем флаг Terminated
|
||||
if Assigned(MyThread2) then
|
||||
MyThread2.Terminate; // Выставляем флаг Terminated
|
||||
MyThread2.Terminate; // Выставляем флаг Terminated
|
||||
end;
|
||||
MyThread1.Free;
|
||||
MyThread2.Free;
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex5Unit;
|
||||
unit Ex5Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -42,7 +42,7 @@ type
|
||||
procedure FormCreate(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FList: TObjectList; // Потоки для первой и второй задачи
|
||||
FList: TObjectList; // Потоки для первой и второй задачи
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
@ -56,7 +56,7 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunParallelThreadsClick(Sender: TObject);
|
||||
begin
|
||||
// Запускаем 4 параллельных потока
|
||||
// Запускаем 4 параллельных потока
|
||||
if FList.Count = 0 then
|
||||
begin
|
||||
FList.Add(TMyLongThread1.Create(1000));
|
||||
@ -70,7 +70,7 @@ end;
|
||||
|
||||
constructor TMyLongThread1.Create(UsefullTaskTime: Integer);
|
||||
begin
|
||||
inherited Create(False); // Вызываем родительский конструктор
|
||||
inherited Create(False); // Вызываем родительский конструктор
|
||||
FUsefullTaskTime := UsefullTaskTime;
|
||||
end;
|
||||
|
||||
@ -79,9 +79,9 @@ begin
|
||||
while not Terminated do
|
||||
begin
|
||||
EmulateUsefullWork(FUsefullTaskTime);
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
end;
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
end;
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
@ -94,16 +94,16 @@ var
|
||||
AProgress: TProgressViewer;
|
||||
I: Integer;
|
||||
begin
|
||||
AProgress := TProgressViewer.Create('Выход из программы');
|
||||
AProgress := TProgressViewer.Create('Выход из программы');
|
||||
try
|
||||
if cbTerminateMode.ItemIndex = 1 then
|
||||
begin // Выбран режим "Одновременно (быстрее)"
|
||||
// Выставляем флаг Terminated для всех потоков. Можно использовать
|
||||
// родительский класс TThread для операции приведения типов.
|
||||
begin // Выбран режим "Одновременно (быстрее)"
|
||||
// Выставляем флаг Terminated для всех потоков. Можно использовать
|
||||
// родительский класс TThread для операции приведения типов.
|
||||
for I := 0 to FList.Count - 1 do
|
||||
TThread(FList[I]).Terminate;
|
||||
end;
|
||||
// При уничтожении списка TObjectList будут уничтожены все объекты потоков
|
||||
// При уничтожении списка TObjectList будут уничтожены все объекты потоков
|
||||
FList.Free;
|
||||
finally
|
||||
AProgress.TerminateProgress;
|
||||
@ -117,9 +117,9 @@ begin
|
||||
while not Terminated do
|
||||
begin
|
||||
EmulateUsefullWork(2000);
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
end;
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
end;
|
||||
|
||||
{ TMyLongThread3 }
|
||||
@ -135,9 +135,9 @@ begin
|
||||
while not Terminated do
|
||||
begin
|
||||
EmulateUsefullWork(FUsefullTaskTime);
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
end;
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
end;
|
||||
|
||||
{ TMyLongThread4 }
|
||||
@ -147,9 +147,9 @@ begin
|
||||
while not Terminated do
|
||||
begin
|
||||
EmulateUsefullWork(1000);
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
ThreadWaitTimeout(Self, 60000); // Ожидаем таймаут 60 сек
|
||||
end;
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
Sleep(5000); // Оставлено для демонстрации режима "Одновременно"
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex6Unit;
|
||||
unit Ex6Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -36,7 +36,7 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunInParallelThreadClick(Sender: TObject);
|
||||
begin
|
||||
// Запускаем параллельный поток
|
||||
// Запускаем параллельный поток
|
||||
TMyThread.Create;
|
||||
end;
|
||||
|
||||
@ -44,13 +44,13 @@ procedure TForm1.FormDestroy(Sender: TObject);
|
||||
var
|
||||
pv: TProgressViewer;
|
||||
begin
|
||||
// Выставляем флаг StopThreadsFlag, чтобы все потоки завершились
|
||||
// Выставляем флаг StopThreadsFlag, чтобы все потоки завершились
|
||||
StopThreadsFlag := True;
|
||||
|
||||
// Задерживаем выход из программы, пока не будут завершены все потоки
|
||||
// Задерживаем выход из программы, пока не будут завершены все потоки
|
||||
if ThreadCount > 0 then
|
||||
begin
|
||||
pv := TProgressViewer.Create('Ожидаем завершение потоков');
|
||||
pv := TProgressViewer.Create('Ожидаем завершение потоков');
|
||||
while ThreadCount > 0 do
|
||||
Sleep(10);
|
||||
pv.TerminateProgress;
|
||||
@ -62,15 +62,15 @@ end;
|
||||
constructor TMyThread.Create;
|
||||
begin
|
||||
inherited Create(False);
|
||||
// Увеличиваем глобальную переменную ThreadCount на 1 и запоминаем
|
||||
// полученное значение
|
||||
// Увеличиваем глобальную переменную ThreadCount на 1 и запоминаем
|
||||
// полученное значение
|
||||
FThreadNum := InterlockedIncrement(ThreadCount);
|
||||
end;
|
||||
|
||||
destructor TMyThread.Destroy;
|
||||
begin
|
||||
inherited;
|
||||
// Уменьшаем глобальную переменную ThreadCount на 1
|
||||
// Уменьшаем глобальную переменную ThreadCount на 1
|
||||
InterlockedDecrement(ThreadCount);
|
||||
end;
|
||||
|
||||
@ -80,17 +80,17 @@ var
|
||||
begin
|
||||
FreeOnTerminate := True;
|
||||
|
||||
// Организуем паузу 10 секунд. При этом каждые 20 мс
|
||||
// проверяем флаг StopThreadsFlag
|
||||
// Организуем паузу 10 секунд. При этом каждые 20 мс
|
||||
// проверяем флаг StopThreadsFlag
|
||||
ti.Start;
|
||||
while ti.ElapsedSeconds < 10 do
|
||||
begin
|
||||
// Заканчиваем ожидание, если выставлен флаг StopThreadsFlag
|
||||
// Заканчиваем ожидание, если выставлен флаг StopThreadsFlag
|
||||
if StopThreadsFlag then Break;
|
||||
Sleep(20);
|
||||
end;
|
||||
|
||||
ThreadShowMessageFmt('Работа потока #%d завершена!', [FThreadNum]);
|
||||
ThreadShowMessageFmt('Работа потока #%d завершена!', [FThreadNum]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -47,7 +47,6 @@ object Form1: TForm1
|
||||
Height = 17
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
TabOrder = 1
|
||||
ExplicitWidth = 519
|
||||
end
|
||||
object edMaxValue: TEdit
|
||||
Left = 232
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex7Unit;
|
||||
unit Ex7Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -41,17 +41,17 @@ implementation
|
||||
|
||||
procedure TForm1.btnRunInParallelThreadClick(Sender: TObject);
|
||||
begin
|
||||
// Уничтожаем запущенный поток
|
||||
// Уничтожаем запущенный поток
|
||||
if Assigned(FMyThread) then
|
||||
FreeAndNil(FMyThread);
|
||||
|
||||
// Создаём поток в спящем состоянии
|
||||
// Создаём поток в спящем состоянии
|
||||
FMyThread := TMyThread.Create(True);
|
||||
|
||||
// Запоминаем длину ряда в поле MaxValue
|
||||
// Запоминаем длину ряда в поле MaxValue
|
||||
FMyThread.MaxValue := StrToIntDef(edMaxValue.Text, 0);
|
||||
|
||||
// Пробуждаем поток для выполнения вычислений
|
||||
// Пробуждаем поток для выполнения вычислений
|
||||
FMyThread.Resume;
|
||||
end;
|
||||
|
||||
@ -67,10 +67,10 @@ var
|
||||
Res: Int64;
|
||||
CurrVal: Integer;
|
||||
begin
|
||||
// Выставляем параметры компонента ProgressBar1
|
||||
// Выставляем параметры компонента ProgressBar1
|
||||
Synchronize(SetProgressParams);
|
||||
|
||||
// Выполняем некоторые вычисления
|
||||
// Выполняем некоторые вычисления
|
||||
Res := 0;
|
||||
CurrVal := 0;
|
||||
while CurrVal < MaxValue do
|
||||
@ -80,14 +80,14 @@ begin
|
||||
Res := Res + CurrVal;
|
||||
|
||||
if CurrVal mod 10000 = 0 then
|
||||
begin // Обновление прогресса выполняется только 1 раз из 10000
|
||||
begin // Обновление прогресса выполняется только 1 раз из 10000
|
||||
FCurrValue := CurrVal;
|
||||
FResult := Res;
|
||||
Synchronize(SetProgressCurrValue);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Обновляем прогресс в конце вычислений
|
||||
// Обновляем прогресс в конце вычислений
|
||||
FCurrValue := CurrVal;
|
||||
FResult := Res;
|
||||
Synchronize(SetProgressCurrValue);
|
||||
|
@ -70,24 +70,6 @@ object Form1: TForm1
|
||||
TabOrder = 2
|
||||
Text = '10000000'
|
||||
end
|
||||
object Button1: TButton
|
||||
Left = 280
|
||||
Top = 88
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = #1058#1077#1089#1090' '#1079#1072#1084#1077#1088#1086#1074
|
||||
TabOrder = 3
|
||||
OnClick = Button1Click
|
||||
end
|
||||
object Button2: TButton
|
||||
Left = 280
|
||||
Top = 120
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Button2'
|
||||
TabOrder = 4
|
||||
OnClick = Button2Click
|
||||
end
|
||||
object Timer1: TTimer
|
||||
Interval = 100
|
||||
OnTimer = Timer1Timer
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit Ex8Unit;
|
||||
unit Ex8Unit;
|
||||
|
||||
interface
|
||||
|
||||
@ -13,7 +13,7 @@ type
|
||||
FResult: Int64;
|
||||
FCurrValue: Integer;
|
||||
|
||||
// Èíôîðìàöèÿ î òåêóùåì ñîñòîÿíèè ïîòîêà
|
||||
// Информация о текущем состоянии потока
|
||||
FThreadStateInfo: string;
|
||||
|
||||
function GetThreadStateInfo: string;
|
||||
@ -24,8 +24,8 @@ type
|
||||
property CalcResult: Int64 read FResult;
|
||||
property CurrValue: Integer read FCurrValue;
|
||||
|
||||
// Ñâîéñòâî äëÿ äîñòóïà ê ñòðîêå FThreadStateInfo ñ ïîìîùüþ
|
||||
// ïîòîêîçàùèùåííûõ ìåòîäîâ GetThreadStateInfo è SetThreadStateInfo
|
||||
// Свойство для доступа к строке FThreadStateInfo с помощью
|
||||
// потокозащищенных методов GetThreadStateInfo и SetThreadStateInfo
|
||||
property ThreadStateInfo: string read GetThreadStateInfo write SetThreadStateInfo;
|
||||
end;
|
||||
|
||||
@ -38,13 +38,9 @@ type
|
||||
Timer1: TTimer;
|
||||
Label2: TLabel;
|
||||
labThreadStateInfo: TLabel;
|
||||
Button1: TButton;
|
||||
Button2: TButton;
|
||||
procedure btnRunInParallelThreadClick(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure Timer1Timer(Sender: TObject);
|
||||
procedure Button1Click(Sender: TObject);
|
||||
procedure Button2Click(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FMyThread: TMyThread;
|
||||
@ -62,7 +58,7 @@ procedure TForm1.btnRunInParallelThreadClick(Sender: TObject);
|
||||
var
|
||||
MaxValue: Integer;
|
||||
begin
|
||||
// Óíè÷òîæàåì çàïóùåííûé ïîòîê
|
||||
// Уничтожаем запущенный поток
|
||||
if Assigned(FMyThread) then
|
||||
FreeAndNil(FMyThread);
|
||||
|
||||
@ -75,34 +71,6 @@ begin
|
||||
FMyThread := TMyThread.Create(MaxValue);
|
||||
end;
|
||||
|
||||
procedure TForm1.Button1Click(Sender: TObject);
|
||||
var
|
||||
p: TTimeIntervalEvents;
|
||||
begin
|
||||
p.StartEvent('Ýòàï 1');
|
||||
Sleep(1);
|
||||
p.StopEvent('Ýòàï 1');
|
||||
|
||||
p.StartEvent('Ýòàï 2');
|
||||
Sleep(20);
|
||||
p.StopEvent('Ýòàï 2');
|
||||
|
||||
ShowMessage(p.GetEventsAsString([eoWriteStartTime, eoWriteAllTime,
|
||||
eoUseMicroSec, eoWriteFromStart, eoWriteBegTime, eoWriteEndTime, eoWriteDate]));
|
||||
//ShowMessage(p.GetEventsAsString([eoUseMicroSec]));
|
||||
end;
|
||||
|
||||
procedure TForm1.Button2Click(Sender: TObject);
|
||||
var
|
||||
p: TTimeInterval;
|
||||
begin
|
||||
//p.Start;
|
||||
p := TTimeInterval.StartNew;
|
||||
Sleep(100);
|
||||
ShowMessageFmt('%s', [FormatDateTime('hh:nn:ss.zzz', p.ElapsedTime)]);
|
||||
ShowMessageFmt('%s', [FormatDateTime('hh:nn:ss.zzz', p.ElapsedTime)]);
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
FreeAndNil(FMyThread);
|
||||
@ -143,19 +111,19 @@ end;
|
||||
|
||||
function TMyThread.GetThreadStateInfo: string;
|
||||
begin
|
||||
// Çàùèùàåì ñòðîêó ñ ïîìîùüþ êðèòè÷åñêîé ñåêöèè. Åñëè å¸ óáðàòü,
|
||||
// òî â ãëàâíîì ïîòîêå ïåðèîäè÷åñêè áóäåò âîçíèêàòü îøèáêà
|
||||
// "Invalid pointer operation" ëèáî "Out of memory"
|
||||
StringProtectSection.Enter; // Âõîäèì â ðåæèì çàùèòû
|
||||
// Защищаем строку с помощью критической секции. Если её убрать,
|
||||
// то в главном потоке периодически будет возникать ошибка
|
||||
// "Invalid pointer operation" либо "Out of memory"
|
||||
StringProtectSection.Enter; // Входим в режим защиты
|
||||
Result := FThreadStateInfo;
|
||||
StringProtectSection.Leave; // Âûõîäèì èç ðåæèìà çàùèòû
|
||||
StringProtectSection.Leave; // Выходим из режима защиты
|
||||
end;
|
||||
|
||||
procedure TMyThread.SetThreadStateInfo(const Value: string);
|
||||
begin
|
||||
StringProtectSection.Enter; // Âõîäèì â ðåæèì çàùèòû
|
||||
StringProtectSection.Enter; // Входим в режим защиты
|
||||
FThreadStateInfo := Value;
|
||||
StringProtectSection.Leave; // Âûõîäèì èç ðåæèìà çàùèòû
|
||||
StringProtectSection.Leave; // Выходим из режима защиты
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user