diff --git a/CalcTimeQuant/CalcTimeQuantUnit.dfm b/CalcTimeQuant/CalcTimeQuantUnit.dfm
index 810ced5..cec3e4e 100644
--- a/CalcTimeQuant/CalcTimeQuantUnit.dfm
+++ b/CalcTimeQuant/CalcTimeQuantUnit.dfm
@@ -5,7 +5,7 @@ object Form1: TForm1
#1055#1088#1086#1075#1088#1072#1084#1084#1072' '#1076#1083#1103' '#1086#1087#1088#1077#1076#1077#1083#1077#1085#1080#1103' '#1076#1083#1080#1090#1077#1083#1100#1085#1086#1089#1090#1080' '#1074#1099#1076#1077#1083#1103#1077#1084#1099#1093' '#1082#1074#1072#1085#1090#1086#1074' '#1074#1088#1077#1084#1077#1085 +
#1080
ClientHeight = 434
- ClientWidth = 646
+ ClientWidth = 730
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@@ -16,7 +16,7 @@ object Form1: TForm1
OnCreate = FormCreate
OnDestroy = FormDestroy
DesignSize = (
- 646
+ 730
434)
PixelsPerInch = 96
TextHeight = 19
@@ -58,6 +58,13 @@ object Form1: TForm1
Height = 19
Caption = #1055#1088#1080#1074#1103#1079#1072#1090#1100' '#1082' '#1103#1076#1088#1091' CPU:'
end
+ object Label5: TLabel
+ Left = 296
+ Top = 83
+ Width = 206
+ Height = 19
+ Caption = #1055#1088#1080#1086#1088#1080#1090#1077#1090' '#1087#1077#1088#1074#1086#1075#1086' '#1087#1086#1090#1086#1082#1072':'
+ end
object edThreadCount: TEdit
Left = 192
Top = 52
@@ -68,7 +75,7 @@ object Form1: TForm1
end
object btnStartThreads: TButton
Left = 304
- Top = 103
+ Top = 110
Width = 297
Height = 41
Caption = #1047#1072#1087#1091#1089#1090#1080#1090#1100' '#1087#1086#1090#1086#1082#1080' '#1085#1072' 10 '#1089#1077#1082#1091#1085#1076
@@ -78,11 +85,12 @@ object Form1: TForm1
object Memo1: TMemo
Left = 8
Top = 167
- Width = 630
+ Width = 714
Height = 259
Anchors = [akLeft, akTop, akRight, akBottom]
ScrollBars = ssVertical
TabOrder = 2
+ ExplicitWidth = 630
end
object clbCPUList: TCheckListBox
Left = 192
@@ -100,6 +108,25 @@ object Form1: TForm1
Caption = #1048#1089#1087#1086#1083#1100#1079#1086#1074#1072#1090#1100' '#1088#1072#1079#1085#1099#1077' '#1087#1088#1080#1086#1088#1080#1090#1077#1090#1099
TabOrder = 4
end
+ object cbPriority: TComboBox
+ Left = 506
+ Top = 80
+ Width = 216
+ Height = 27
+ Style = csDropDownList
+ ItemHeight = 19
+ ItemIndex = 3
+ TabOrder = 5
+ Text = 'tpNormal '
+ Items.Strings = (
+ 'tpIdle '
+ 'tpLowest '
+ 'tpLower '
+ 'tpNormal '
+ 'tpHigher '
+ 'tpHighest'
+ 'tpTimeCritical')
+ end
object Timer1: TTimer
Interval = 500
OnTimer = Timer1Timer
diff --git a/CalcTimeQuant/CalcTimeQuantUnit.pas b/CalcTimeQuant/CalcTimeQuantUnit.pas
index 8af738c..f35a4ae 100644
--- a/CalcTimeQuant/CalcTimeQuantUnit.pas
+++ b/CalcTimeQuant/CalcTimeQuantUnit.pas
@@ -38,6 +38,8 @@ type
Label4: TLabel;
clbCPUList: TCheckListBox;
cbUseDiffPriority: TCheckBox;
+ Label5: TLabel;
+ cbPriority: TComboBox;
procedure btnStartThreadsClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -63,8 +65,8 @@ var
APriority: TThreadPriority;
begin
Memo1.Clear;
- //APriority := tpNormal;
- APriority := tpHigher;
+
+ APriority := TThreadPriority(cbPriority.ItemIndex);
for I := 1 to StrToInt(edThreadCount.Text) do
begin
if cbUseDiffPriority.Checked and (I > 1) then
diff --git a/multithread_in_delphi_for_beginners.md b/multithread_in_delphi_for_beginners.md
index 755ef87..f2eada8 100644
--- a/multithread_in_delphi_for_beginners.md
+++ b/multithread_in_delphi_for_beginners.md
@@ -128,13 +128,13 @@ Delphi – это прежде всего инструмент для разра
# 2. Базовый класс многопоточности - TThread
-TThread – это базовый класс, инкапсулирующий функционал для обеспечения работы параллельного потока. Если мы хотим реализовать код, который должен выполняться в отдельном потоке, то нам необходимо реализовать наследника от класса TThread и, как минимум, реализовать override-метод Execute. Код, находящийся внутри метода Execute будет исполняться в отдельном потоке.
+`TThread` – это базовый класс, инкапсулирующий функционал для обеспечения работы параллельного потока. Если мы хотим реализовать код, который должен выполняться в отдельном потоке, то нам необходимо реализовать наследника от класса `TThread` и, как минимум, реализовать override-метод Execute, который перекроет виртуальный абстрактный метод `Execute`, объявленный в родительском классе `TThread`. Код, находящийся внутри метода `Execute` будет исполняться в отдельном потоке.
-При создании класса-наследника от TThread мы можем реализовать конструктор, деструктор, объявить собственные поля, методы, свойства и т.д., в зависимости от поставленной перед нами задачи.
+При создании класса-наследника от `TThread` мы можем реализовать конструктор, деструктор, объявить собственные поля, методы, свойства и т.д., в зависимости от поставленной перед нами задачи.
В данном разделе я не буду подробно останавливаться на описании возможностей класса TThread. Читайте внимательно следующие разделы, надеюсь, в них Вы найдёте необходимую для Вас информацию.
-:information_source: **Информация!** *Дополнительные потоки создаются с помощью вызова соответствующей функции операционной системы, например CreateThread в ОС Windows. Класс TThread является обёрткой, которая добавляет к системному дополнительному потоку объектно-ориентированное измерение, т.е. позволяет создать объект, который привязывается к системному дополнительному потоку.*
+:information_source: **Информация!** *Дополнительные потоки создаются с помощью вызова соответствующей функции операционной системы, например `CreateThread` в ОС Windows. Класс `TThread` является обёрткой, которая добавляет к системному дополнительному потоку объектно-ориентированное измерение, т.е. позволяет создать объект, который привязывается к системному дополнительному потоку.*
:information_source: **Информация!** Существуют и другие популярные средства для многопоточного программирования в Delphi. К ним стоит отнести:
\- **Parallel programming library** - стандартная библиотека для параллельного программирования в современных версиях Delphi.
@@ -972,6 +972,8 @@ end.
8) Кнопка `btnRunInParallelThread` может быть нажата произвольное количество раз.
+:warning: **Внимание!** *Функции `InterlockedIncrement` и `InterlockedDecrement` являются частью Windows API. В современных версиях Delphi Вы можете использовать их кроссплатформенные аналоги: `AtomicIncrement` и `AtomicDecrement`*.
+
# 5. Передача информации из дополнительного потока в основной
При разработке многопоточных приложений в Delphi очень актуальной является задача передачи информации, подготовленной в дополнительном потоке, в главный поток. Это весьма сложная тема, требующая от Delphi-программиста повышенного внимания, т.к. при недостаточных знаниях у программиста есть очень высокий шанс сделать программу глюченной и нестабильной.
@@ -1972,14 +1974,17 @@ end;
tpTimeCritical) platform;
{$ENDIF MSWINDOWS}
```
-Обычно программисту нет смысла изменять приоритеты потоков. Приоритет потока никак не влияет на скорость исполнения программного кода. Приоритет потока никак не влияет на размер кванта времени. Относительный приоритет потока работает только в рамках процесса и никак не влияет на выделение квантов времени потокам, которые работают в других процессах.
+Обычно программисту нет смысла изменять приоритеты потоков. Приоритет потока никак не влияет на скорость исполнения программного кода. Приоритет потока никак не влияет на размер кванта времени (однако размер кванта времени зависит от того, является ли приложение активным или нет, т.е. у неактивного приложения квант времени примерно в 3 раза меньше, чем у активного).
-Изменять приоритет потока не имеет никакого смысла, если выполняется задача, в которой основное время уходит на ожидание какого-либо события.
+Относительный приоритет потока влияет на выделение процессорного времени как между потоками в рамках одного процесса, так и между потоками различных процессов.
+
+Изменять приоритет потока не имеет смысла, если выполняется задача, в которой основное время уходит на ожидание какого-либо события.
Если в Вашей программе работают 2 потока, у одного приоритет `tpNormal`, а у второго `tpLower` и оба потока привязаны к одному и тому же ядру процессора, то первому потоку гораздо чаще будет предоставляться процессорное время (например, 98%). С другой стороны, если у этих же потоков не будет привязки к одному и тому же ядру, то они получат одинаковое процессорное время. Скорее всего, оба варианта – это не то, чего Вы хотите добиться при изменении относительного приоритета потока.
Существует 2 крайних уровня приоритетов: `tpIdle` и `tpTimeCritical`. Поток с приоритетом `tpIdle` получит процессорное время только в том случае, если нет других активных потоков с более высоким приоритетом. Поток с приоритетом `tpTimeCritical` будет забирать себе всё процессорное время, т.е. потоки с более низким приоритетом не получат квант времени, если выполняется поток с приоритетом `tpTimeCritical`. Это верно для одноядерного процессора. Если процессор многоядерный (сейчас это обычная ситуация), то, скорее всего, будут выполняться одновременно и поток с приоритетом `tpIdle` и поток с приоритетом `tpTimeCritical`.
+:information_source: **Внимание!** *В каталоге CalcTimeQuant находится программа, позволяющая производить эксперименты с приоритетами и замеры длительности квантов времени.*