powered by simpleCommunicator - 2.0.29     © 2024 Programmizd 02
Map
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Многопоточное программирование в Delphi для начинающих
160 сообщений из 160, показаны все 7 страниц
Многопоточное программирование в Delphi для начинающих
    #39977356
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Работаю над учебником "Многопоточное программирование в Delphi для начинающих".
Учебник вместе с примерами доступен по ссылке: https://github.com/loginov-dmitry/multithread
Примеры должны компилироваться во всех версиях Delphi, начиная с Delphi 2007 (кроме примера Ex12, где рассматривается метод Queue).
В настоящее время в учебнике 58 страниц. Описаны минимальные базовые вещи, которые позволят начинающему разобраться с многопоточностью и начать разработку реальных проектов.
Прошу отнестись к данной работе критически, т.к. есть желание (цель) давать ссылки на данный учебник при возникновении вопросов по многопоточности. Я потратил на эту работу в сумме около месяца и будет обидно читать комментарии типа "на второй странице пропущена запятая, значит всё там неправильно и читать дальше не буду".

К сожалению, я успел описать далеко не всё, что хотелось бы. Надеюсь, что мне удастся и дальше продолжить эту работу (не в ущерб основной работе).

В настоящее время оглавление следующее:
Оглавление1. Вступление
1.1 Для чего используется многопоточное программирование в Delphi
1.2 В чём сложность разработки многопоточных программ в Delphi по сравнению с другими современными языками программирования
1.3 Поддержка многопоточности в операционных системах и процессорах
2. Базовый класс многопоточности - TThread
3. Предотвращаем зависание основного потока (имитация задачи длительного вычисления)
4. Управление временем жизни потоков
4.1 Использование свойства TThread.Terminated для выхода из метода Execute
4.2 Главная форма отвечает за прекращение работы потока и уничтожение объекта потока
4.3 Главная форма отвечает за уничтожение объекта потока с разовой задачей 17стр.
4.4 Главная форма отвечает за уничтожение нескольких долгоживущих потоков 19
4.5 Использование списка TObjectList для хранения ссылок на объекты потоков 23
4.6 Простой пример организации паузы в работе потока 26
4.7 Использование свойства FreeOnTerminate для автоматического уничтожения объекта потока при завершении работы потока 27
4.8 Организация корректного завершения работы программы при использовании свойства FreeOnTerminate 28
5. Передача информации из дополнительного потока в основной 32
5.1 Обращение к визуальным компонентам формы из дополнительного потока – как нельзя делать 32
5.2 Использование метода TThread.Synchronize для передачи данных в основной поток 32
5.3 Периодическое чтение основным потоком данных, подготовленных в дополнительном потоке 36
5.4 Использование функции SendMessage для передачи данных в основной поток 40
5.5 Использование функции PostMessage для передачи очереди сообщений в основной поток 44
5.6 Использование списка TThreadList для передачи очереди данных в основной поток 46
5.7 Использование метода TThread.Synchronize для передачи данных в основной поток – вариант с использованием анонимной процедуры 50
5.8 Использование метода TThread.Queue для передачи данных в основной поток 51
6. Где можно и где нельзя создавать и уничтожать потоки 57
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977399
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,

привет, начал читать. Что касается "запятых" ("а второй странице пропущена запятая...") то по-моему как раз язык нормальный, мысли пока что, сколько прочитал, были по-моему выражены ясно. )
Дочитал до начала описания класса TThread. Мне показалось, что есть "дырка" в изложении - переход от общего описания многопоточности в ОС к классу TThread. Может быть стоит написать про функцию CreateThread, при помощи которой можно создать поток в вызывающем её процессе (более строго, по документации: "который выполняется в адресном пространстве вызывающего процесса") и которую TThread инкапсулирует?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977425
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62
DmSer,

привет, начал читать. Что касается "запятых" ("а второй странице пропущена запятая...") то по-моему как раз язык нормальный, мысли пока что, сколько прочитал, были по-моему выражены ясно. )
Дочитал до начала описания класса TThread. Мне показалось, что есть "дырка" в изложении - переход от общего описания многопоточности в ОС к классу TThread. Может быть стоит написать про функцию CreateThread, при помощи которой можно создать поток в вызывающем её процессе (более строго, по документации: "который выполняется в адресном пространстве вызывающего процесса") и которую TThread инкапсулирует?


Спасибо за предложение! Но мне кажется, это будет лишняя информация для начинающих. Очень сложно разобраться, какой материал нужно включать, какой не нужно. Тонкостей различных миллион! Если описывать про CreateThread, а это чисто виндовая функция, тогда придётся описывать аналоги и в других ОС (Linux, MacOS, Android). Вероятно, можно будет обойтись более общей формулировкой о том, что доп. поток на самом деле создаёт ОС, а класс TThread является обёрткой...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977434
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSerЕсли описывать про CreateThread, а это чисто виндовая функция

Причём такая, которой не надо пользоваться практически никогда. _beginthreadex() описать
таки надо. Хотя бы пробы было понимание, что "TThread это не поток".
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977473
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Вероятно, можно будет обойтись более общей формулировкой о том, что доп. поток на самом деле создаёт ОС, а класс TThread является обёрткой...
Ну да, можно и как-то так.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977483
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

так вот почему такой странный топик про потоки. А я-то воспринял, как будто новичок украл твой ник и забавляется. Извини за наезд :)

Исходник книги на чем пишешь? Я тут кое-что время от времени перевожу, из markdown экспортируется весьма читабельно, а у тебя бледненько - текст труднее воспринимается
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977500
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer> Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

Это дело хорошее, полезное. Научный редактор есть
или ты надеешься на краудсорсинговую вычитку?

> Примеры должны компилироваться во всех версиях Delphi, начиная
> с Delphi 2007 (кроме примера Ex12, где рассматривается метод Queue).

В Д7 не проверялось?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977510
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чтобы разрабатывать реальные проекты надо не многопоточность изучать, а терминологию и практики...

Очень хороший пример всего этого описан в ответе здесь .

Далее.. Delphi сейчас - это кроссплатформенная среда разработки, следовательно все примеры должны быть кроссплатформенные.
Все что в современной версии досталось в наследство от 1-7 версий должно быть похоронено как deprecated.
У этого всего давно появились другие аналоги, более удобные в проектировании и разработке.

Как минимум уже в начале неверно описана область применения PPL.
PPL - это способ выполнить некую работу (не важно какую, абсолютно любую) конкурентно не вдаваясь в детали реализации. Как она будет выполнена: параллельно, асинхронно или синхронно - это дело десятое и в современно мире особо об этом задумываться ненужно. Когда над проектом работают десятки разработчиков, порог входа должен быть низкий, чтобы иметь возможность дешево менять ресурсы, для этого и придумывают различные библиотеки и абстракции, которые в освоении намного проще.

Проблема в Дельфи в том, что разработчики которые туда пытаются придти учатся по книжкам которые написаны были во времена высокого порога входа в программирование, а не когда курсы клепают по 100 "программистов" в день...

Поэтому лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977518
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторЯ хотел бы выделить две основные причины использования многопоточности в Delphi-программах
Задачи длительного ожидания завершения ввода-вывода.
Вы путаете теплое с мягким. Такие задачи должны выполняться асинхронно.. Другой поток - это способ реализации, при чем довольно не эффективный, если таких запросов много.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977551
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Первый пример показан через оверхед.
Намного лаконичнее решается через
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TThread.CreateAnonymousThread(
    procedure
    var
      V: Int64;
    begin
      V := DoLongCalculations;
      MyShowMessage('Результат: ' + IntToStr(V));
    end
  ).Start();


И кстати, такая вариация намного удачнее, чем через отдельный класс, потому что явно видно в каком месте какую работу необходимо выполнить в потоке отличном от вызываемого.
А еще лучше так никогда не делать и не показывать что вообще можно...
Потому что
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TTask.Run(
    procedure
    var
      V: Int64;
    begin
      V := DoLongCalculations;
      MyShowMessage('Результат: ' + IntToStr(V));
    end
  );


намного лучше, т.к. нет оверхеда на создание/разрушение потоков

Лучше учить решать задачи наиболее подходящим инструментом, чем учить использовать примитив везде где попало.

Иначе книжку надо переименовать в Работа с классом TThread, а не многопоточное программирование...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977556
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.
Если человек не понимает (и/или не знает), как работает под капотом, то при первой же проблеме ему придётся либо разобраться в этом, либо сменить профессию.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977558
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Код: pascal
1.
TTask.Run


Что будет, если DoLongCalculations будет выполняться часами, а пользователь захочет закрыть программу?
Нежданчик?
И таким "современным" методам вы предлагаете учить молодежь? Чтобы они и не знали, как сделать по-нормальному, чтобы контролировать всё?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977559
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock,

Почти все проблемы для известных и популярных библиотек уже описаны и описаны способы решения. В том числе например и для PPL. Проще обучить как решать задачи для которых PPL предпочтительнее, чем решать эти же задачи на TThread
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977560
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
YuRock,

Почти все проблемы для известных и популярных библиотек уже описаны и описаны способы решения. В том числе например и для PPL. Проще обучить как решать задачи для которых PPL предпочтительнее, чем решать эти же задачи на TThread
Проблемы всегда появляются в логике решения любой задачи.
Какие нафиг библиотеки, я не про них говорю, а про реальные проекты, которые будут делать программисты.
Научить TTask'у, конечно, проще, чем TThread'у, только толку от этого ученика не будет.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977562
Vizit0r
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock
X-Cite
Код: pascal
1.
TTask.Run


Что будет, если DoLongCalculations будет выполняться часами, а пользователь захочет закрыть программу?
Нежданчик?

жданчик будет. Ошибки, зависания, прочие прелести.
Я от TTask отказался как раз из-за абсолютно фантастических вещей при его остановке.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977580
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock

Что будет, если DoLongCalculations будет выполняться часами, а пользователь захочет закрыть программу?


Тоже самое что и в TThread.Execute(), но в отличие от TThread бизнес-единица алгоритма будет всегда в согласованном состоянии.

Примеры:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
  TThread.CreateAnonymousThread(
    procedure
    var
      a: TArray<Byte>;
    begin
      for var k := 1 to 10 do
      begin
        SetLength(a, 1024 * 1024 * 500);
        FillChar(a[0], 1024 * 1024 * 500, 5);
        TFile.WriteAllBytes('C:\TThread.txt', a);
      end;
    end
  ).Start();
  Application.Terminate;


Что будет? Access Violation будет. Отстрелили ногу.
TTask.Run - корректно дождется конца.

т.е. в TThread как минимум надо самостоятельно ждать окончания работы, чтобы корректно продолжить.

Что надо сделать чтобы не ждать конца?
А закончить работу пораньше.

Одно и тоже, что в TTask что в TThread - только способы реализации будут разные.

Только с CreateAnonymousThread - все намного сложнее, окей, применяем старый подход через отдельный класс

Реализация для TThread
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: TThread;
begin
  x := TMyThread.Create();
  try
    while not x.Started do
      ; // Убеждаемся что поток начал работу
    x.Terminate();
    x.WaitFor();
  finally
    x.Free();
  end;
  Application.Terminate();
end;

{ TMyThread }

procedure TMyThread.Execute;
var
  a: TArray<Byte>;
begin
  for var k := 1 to 3 do
  begin
    SetLength(a, 1024 * 1024 * 500);
    FillChar(a[0], 1024 * 1024 * 500, 5);
    if Terminated then
      Exit;
    TFile.WriteAllBytes('C:\TThread.txt', a);
  end;
end;



Реализация для TTask
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
procedure TForm1.Button2Click(Sender: TObject);
var
  x: ITask;
begin
  x := TTask.Run(
    procedure
    var
      a: TArray<Byte>;
    begin
      for var k := 1 to 3 do
      begin
        SetLength(a, 1024 * 1024 * 500);
        FillChar(a[0], 1024 * 1024 * 500, 5);
        if TTask.CurrentTask.Status = TTaskStatus.Canceled then
          Exit;
        TFile.WriteAllBytes('C:\TTask.txt', a);
      end;
    end
  );
  while x.Status <> TTaskStatus.Running do
    ; // Убеждаемся что задача начала выполнятся
  x.Cancel();
  Application.Terminate();
end;



И что мы видим... Работает и то и то.
Но преимущества TTask
1) Код не размазан и лаконичен
2) Нет оверхеда на создание/уничтожение потоков
3) Задачу выполнения работы решает не примитив (поток), а инструмент (задача) который по факту может ее решить как угодно, вплоть до делегирования другому процессу.

Вы как поставите задачу подчиненному программисту?
1) Произвести запись в файл асинхронно.
2) Произвести запись в файл используя отдельный поток.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977598
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite

Что будет? Access Violation будет.

С чего бы? GUI-поток завершится, но это не беда. Процесс будет жить, пока другой поток (другие потоки) не закончит свою работу. Вторичному потоку, который пишет в файл, от бывшего главного вроде бы ничего не нужно. Допишет файл, и тихо выйдет. По идее. На практике не проверил. Единственно, что вызывает сомнения - не будет ли сломан менеджер памяти, который должен на выходе из процедуры освободить байтовый массив. На первый взгляд, не будет.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977632
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док

так вот почему такой странный топик про потоки. А я-то воспринял, как будто новичок украл твой ник и забавляется. Извини за наезд :)


Все нормально! У меня в тот момент возникли сложности с тем, как лучше описать Queue. Не получалось её описать в позитивном ключе. А тему завел по причине того, что у некоторых разработчиков на этом форуме есть положительный опыт и позитивные отзывы. В результате та тема мне очень помогла, удалось очень подробно описать Queue в позитивном ключе. А кое-кто писал, что на оф. сайте по Queue всё есть, головой только немного подумать нужно. Ну да, я подумал, разобрался (вроде), но страшно представить, сколько времени уйдет у новичка, если он будет методом тыка все грабли перебирать.


Док

Исходник книги на чем пишешь? Я тут кое-что время от времени перевожу, из markdown экспортируется весьма читабельно, а у тебя бледненько - текст труднее воспринимается


Пишу в ворде 2010года. Про markdown не знал, спасибо. Почитаю, пока отпуск!
В идеале хотелось бы пользоваться специализированным решением, которое было бы совместимо с системой контроля версий. Но при этом не тратить много времени.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977636
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов Рустам
DmSer> Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

Это дело хорошее, полезное. Научный редактор есть
или ты надеешься на краудсорсинговую вычитку?


Я надеюсь, что если там есть откровенная лажа, то она без внимания не останется :)
При этом понимаю, что читать 58 страниц такого текста - это не роман прочитать. За час не управишься! :)

Гаджимурадов Рустам

> Примеры должны компилироваться во всех версиях Delphi, начиная
> с Delphi 2007 (кроме примера Ex12, где рассматривается метод Queue).

В Д7 не проверялось?


Я использую модуль TimeIntervals, там есть класс TTimeInterval, который является рекордом с методами. В D7 такое не скомпилится. Также я предполагаю, что в D7 были бы проблемы с отображением исходников в кодировке UTF-8. А мне приходится использовать UTF-8 для корректного отображения в гитхабе.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977638
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Чтобы разрабатывать реальные проекты надо не многопоточность изучать, а терминологию и практики...

Очень хороший пример всего этого описан в ответе здесь .

Далее.. Delphi сейчас - это кроссплатформенная среда разработки, следовательно все примеры должны быть кроссплатформенные.
Все что в современной версии досталось в наследство от 1-7 версий должно быть похоронено как deprecated.
У этого всего давно появились другие аналоги, более удобные в проектировании и разработке.

Как минимум уже в начале неверно описана область применения PPL.
PPL - это способ выполнить некую работу (не важно какую, абсолютно любую) конкурентно не вдаваясь в детали реализации. Как она будет выполнена: параллельно, асинхронно или синхронно - это дело десятое и в современно мире особо об этом задумываться ненужно. Когда над проектом работают десятки разработчиков, порог входа должен быть низкий, чтобы иметь возможность дешево менять ресурсы, для этого и придумывают различные библиотеки и абстракции, которые в освоении намного проще.

Проблема в Дельфи в том, что разработчики которые туда пытаются придти учатся по книжкам которые написаны были во времена высокого порога входа в программирование, а не когда курсы клепают по 100 "программистов" в день...

Поэтому лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.


Я достаточно много думал о том, нужно ли описывать базовые вещи, или сразу начать с PPL. Моя уверенность в том, что важнее описать базовые вещи укрепилась после серии вопросов на этом форуме, которые относятся к PPL, а также к CreateAnonymousThread от начинающих программистов и не очень. Да, начинающего программиста можно, как мартышку, научить выполнять конкретное действие через TTask.Run. Но он нихрена не понимает, как это работает, если не знает базовые вещи. Проблема в Дельфи в том, что там нет того асинхронного программирования, которое есть в C#, JavaScript, Rust, Kotlin и некоторых других ЯП. В ЯП, где есть асинхронная конструкция async/await (либо аналоги), программисты решают реальные бизнес-задачи и как раз там им не требуется задумываться о том, как задача будет выполнена: параллельно, асинхронно или синхронно. В языках, которые изначально спроектированы как многопоточные (имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977641
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
авторЯ хотел бы выделить две основные причины использования многопоточности в Delphi-программах
Задачи длительного ожидания завершения ввода-вывода.

Вы путаете теплое с мягким. Такие задачи должны выполняться асинхронно.. Другой поток - это способ реализации, при чем довольно не эффективный, если таких запросов много.

Да, должны! Но какого объёма книжку нужно написать для начинающего, чтобы он смог написать красивую, надёжную, быструю программу с использованием, скажем Overbyte ICS? А будет ли он читать такую книгу? А что ему даст асинхронность Overbyte ICS (какое преимущество), если ему потребовалось запрос к БД выполнить? А будет ли он читать такую книгу, если тут на форуме все примеры в основном на Indy?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977645
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite

Потому что
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TTask.Run(
    procedure
    var
      V: Int64;
    begin
      V := DoLongCalculations;
      MyShowMessage('Результат: ' + IntToStr(V));
    end
  );


намного лучше, т.к. нет оверхеда на создание/разрушение потоков

Лучше учить решать задачи наиболее подходящим инструментом, чем учить использовать примитив везде где попало.

Иначе книжку надо переименовать в Работа с классом TThread, а не многопоточное программирование...


В интернете достаточно хороших примеров того, как использовать PPL. Мне и добавить к ним нечего. Пусть начинающие учатся по этим примерам, ради Бога! Если удастся работать эффективно, я буду только рад за них.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977655
Фотография Dmitry Arefiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хорошо работающая PPL это благо для начинающих (и не только).
Либо заголовок не правильный, либо план учебника ...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977656
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
procedure TForm1.Button2Click(Sender: TObject);
var
  x: ITask;
begin
  x := TTask.Run(
    procedure
    var
      a: TArray<Byte>;
    begin
      for var k := 1 to 3 do
      begin
        SetLength(a, 1024 * 1024 * 500);
        FillChar(a[0], 1024 * 1024 * 500, 5);
        if TTask.CurrentTask.Status = TTaskStatus.Canceled then
          Exit;
        TFile.WriteAllBytes('C:\TTask.txt', a);
      end;
    end
  );
  while x.Status <> TTaskStatus.Running do
    ; // Убеждаемся что задача начала выполнятся
  x.Cancel();
  Application.Terminate();
end;

.


И тут блестящая PPL разом превратилась в тыкву! Оказывается, как и с TThread, нужно останавливать таски перед завершением программы, а в таске проверять необходимость завершения :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977661
Фотография Dmitry Arefiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Оказывается ...

Так ты знаешь PPL или только TThread ? :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977663
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry Arefiev
Хорошо работающая PPL это благо для начинающих (и не только).
Либо заголовок не правильный, либо план учебника ...


Возможно в будущем появятся разделы, посвящённые PPL. Тем более PPL все активнее вторгается в нашу жизнь :) Но и помимо PPL есть много тем, которые хотелось бы описать (например, руки пока не дошли до описания темы синхронизации между потоками, а это, я считаю, очень важно). Но благодаря реализации функции ThreadWaitTimeout удаётся до последнего оттягивать такую сложную для понимания тему, как эвенты.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977664
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry Arefiev
DmSer
Оказывается ...

Так ты знаешь PPL или только TThread ? :)


Я изучал довольно много материала по PPL, смотрел видео-уроки, проводил некоторые эксперименты, так что считаю, что знаю о ней достаточно много.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977677
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
X-Cite
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
procedure TForm1.Button2Click(Sender: TObject);
var
  x: ITask;
begin
  x := TTask.Run(
    procedure
    var
      a: TArray<Byte>;
    begin
      for var k := 1 to 3 do
      begin
        SetLength(a, 1024 * 1024 * 500);
        FillChar(a[0], 1024 * 1024 * 500, 5);
        if TTask.CurrentTask.Status = TTaskStatus.Canceled then
          Exit;
        TFile.WriteAllBytes('C:\TTask.txt', a);
      end;
    end
  );
  while x.Status <> TTaskStatus.Running do
    ; // Убеждаемся что задача начала выполнятся
  x.Cancel();
  Application.Terminate();
end;


.


И тут блестящая PPL разом превратилась в тыкву! Оказывается, как и с TThread, нужно останавливать таски перед завершением программы, а в таске проверять необходимость завершения :)


Это еще не идёт речь о том, что часто потоки нужно завершать в определенном порядке. Как это сделать с тасками - объяснить начинающему программисту будет проблематично :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977688
Фотография Дегтярев Евгений
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
(имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!

ты про шедулершедулер или gc?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977701
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дегтярев Евгений
DmSer
(имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!

ты про шедулершедулер или gc?


Раньше кооперативный планировщик был, а работу планировщика ОС они грубо говоря игнорировали. Теперь учитывают.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977717
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock

Это еще не идёт речь о том, что часто потоки нужно завершать в определенном порядке. Как это сделать с тасками - объяснить начинающему программисту будет проблематично :)


Опять путаница между теплым и мягким.

Есть различные задачи, которые надо реализовать.
Эти все задачи можно и нужно отнести к определенным классам задач.
И здесь вступает в игру то, что для разных классов задач, подходят разные решения.

Если говорить о Delphi, то для класса задач асинхронного ожидания ответа или исполнения лучше подходят TTask.
Для класса задач распараллеливания лучше подходит TParallel.
Для класса задач фонового (долгого, постоянного, возможно на время жизни всего приложения) выполнения (То о чем тут чаще всего говорят) к сожалению нет никакого BackgroundService который бы умел и зависимости разруливать и шедулер иметь нормальный и прочее, но из того что есть лучше подходит как раз TThread.

На самом деле TThread - это класс для выполнения фоновых (долгоиграющих) задач.

Если говорить о теме топика, то я не понимаю что такое многопоточное программирование. Есть решение задач с помощью потоков - это уже звучит по другому. И как минимум понятно, что не все задачи можно и нужно решать с помощью потоков.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977880
Фотография Дегтярев Евгений
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Дегтярев Евгений
пропущено...
ты про шедулершедулер или gc?

Раньше кооперативный планировщик был, а работу планировщика ОС они грубо говоря игнорировали. Теперь учитывают.

видимо у авторов были веские причины запилить это, но как по мне оно решает настолько нетипичную для гошного кода ситуацию
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977947
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня ощущение, что многие критикующие пропустили важные слова - "для начинающих".
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977984
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Если говорить о теме топика, то я не понимаю что такое многопоточное программирование. Есть решение задач с помощью потоков - это уже звучит по другому. И как минимум понятно, что не все задачи можно и нужно решать с помощью потоков.
Это умение "сшивать" взаимодействие потоков и знать как использовать различные способы синхронизации. А что-то там считать - ничем от однопоточного не отличается
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977988
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X-Cite
Проблема в Дельфи в том, что разработчики которые туда пытаются придти учатся по книжкам которые написаны были во времена высокого порога входа в программирование, а не когда курсы клепают по 100 "программистов" в день...

Поэтому лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.

1. проблема в том, что такие "программисты" никому и не нужны - если они не чисто за корочкой идут
2. нету реальных бизнес-задач с потоками, которые могут решать "прошедшие курсы" :-)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977993
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman
У меня ощущение, что многие критикующие пропустили важные слова - "для начинающих".

просто пиписьками меряются друг перед другом. Другого объяснения нет
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39977998
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,
я не уверен, но может быть при ручном убиении потока кошернее делать экземпляру потока не просто Free, а Free + Nil?

Я обычно провожу проверку на существование предыдущего экземпляра прежде, чем запустить новый, типа:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
type
Form1 = class(TForm)
...
private
FMyThread: TMyThread;
...
end;

procedure Button1Click...
begin
  //если сделать просто FMyThread.Free, то праздника не получится
  if Assigned(FMyThread) the Exit;
  ...
end;
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39978161
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
DmSer,
я не уверен, но может быть при ручном убиении потока кошернее делать экземпляру потока не просто Free, а Free + Nil?

Я обычно провожу проверку на существование предыдущего экземпляра прежде, чем запустить новый, типа:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
type
Form1 = class(TForm)
...
private
FMyThread: TMyThread;
...
end;

procedure Button1Click...
begin
  //если сделать просто FMyThread.Free, то праздника не получится
  if Assigned(FMyThread) the Exit;
  ...
end;



Конечно, так и нужно. А в каком примере nil отсутствует? Вроде следил, чтобы везде было!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39978165
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
А в каком примере nil отсутствует?

Код: pascal
1.
2.
3.
4.
5.
6.
7.
procedure TForm1.FormDestroy(Sender: TObject);
begin
  // При закрытии программы необходимо завершить работу потока
  // и уничтожить объект потока MyThread
  if MyThread <> nil then
    MyThread.Free;
end;


стр 16
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39978195
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
DmSer
А в каком примере nil отсутствует?

Код: pascal
1.
2.
3.
4.
5.
6.
7.
procedure TForm1.FormDestroy(Sender: TObject);
begin
  // При закрытии программы необходимо завершить работу потока
  // и уничтожить объект потока MyThread
  if MyThread <> nil then
    MyThread.Free;
end;


стр 16


Здесь нормально, тут же FormDestroy! Есть примеры, где объект потока уничтожается при нажатии на кнопку, вот там ссылка обнуляется и есть объяснение зачем это делается.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39978490
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,
Респект за работу!

Рекомендую назвать материал - "Памятка изучающим (многопоточное программирование на) Delphi TThread"

(руки пока не дошли до описания темы синхронизации между потоками, а это, я считаю, очень важно).
Мдя... (может рассказать о нескольких способах кормления философов на примерах?)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39978532
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bred eFeM
Мдя... (может рассказать о нескольких способах кормления философов на примерах?)


Я не уверен в пользе такого подхода. Помню, на 2-м или 3-м курсе университета были занятия, на которых преподавали многопоточность по философам ( библиотека Gala ), анимация интересная, но вряд ли кто-то из студентов смог извлечь из неё что-то полезное. А преподаватель вообще был не знаком с этой библиотекой :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39984742
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Учебник сохранён в формате markdown. Очень удобная вещь оказалась. Текст в итоге читается вроде не хуже, чем в docx. ссылка
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39984773
white_nigger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не понравилось буквально в первом примере это:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
procedure TMyThread.Execute;
var
  V: Int64;
begin
  FreeOnTerminate := True;
  V := DoLongCalculations;
  MyShowMessage('Результат: ' + IntToStr(V));
end;


Как только начинающий захочет заменить MyShowMessage на показ своей супер-пупер формы - он может нехило обломаться. Обязательно надо подчеркнуть что все UI вещи (по крайней мере VCL) надо выполнить в Synchronize или Queue. Понятно что в примере голый WinApi и там и так прокатит, но лучше сразу показать. Вместо апишного вызова лучше взять делфёвый ShowMessage
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39984786
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
white_nigger
Не понравилось буквально в первом примере это:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
procedure TMyThread.Execute;
var
  V: Int64;
begin
  FreeOnTerminate := True;
  V := DoLongCalculations;
  MyShowMessage('Результат: ' + IntToStr(V));
end;


Как только начинающий захочет заменить MyShowMessage на показ своей супер-пупер формы - он может нехило обломаться. Обязательно надо подчеркнуть что все UI вещи (по крайней мере VCL) надо выполнить в Synchronize или Queue. Понятно что в примере голый WinApi и там и так прокатит, но лучше сразу показать. Вместо апишного вызова лучше взять делфёвый ShowMessage


В пояснении к этому примеру приводится необходимая информация о MyShowMessage и ShowMessage. Это сделано специально, чтобы читатель не пытался вызывать ShowMessage из доп. потока.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39984976
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пробежал по диагонали. Классная статья получилась. Для полноты картины еще бы неплохо добавить разделы про эвенты, мьютексы, семафоры. Я, например, про эвенты кое-как наскреб инфу в инете, потому методом проб и ошибок дотумкал, как они работают :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985017
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
Пробежал по диагонали. Классная статья получилась. Для полноты картины еще бы неплохо добавить разделы про эвенты, мьютексы, семафоры. Я, например, про эвенты кое-как наскреб инфу в инете, потому методом проб и ошибок дотумкал, как они работают :)


Спасибо!

Эвенты, мьютексы и семафоры - очень сложная часть. Пока не придумал, как это влить в статью. Мьютексы может сейчас и не особенно актуальны. На своей практике могу сказать, что мьютексы полезны в случае, если нужно синхронизировать работу нескольких экземпляров программы (в том числе реализовать контроль повторного запуска приложения). В рамках одной программы они не нужны, можно их заменить крит. секцией либо TMonitor. Эвенты чаще используем, но только в рамках одной программы (т.е. без межпроцессного взаимодействия). В основном в обмене по RS-232. TMonitor их также может заменить. Семафоры вообще не используем, имхо, проще использовать крит.секцию + счётчик чем разбираться с ещё одним объектом синхронизации.
Нужно ещё учитывать кроссплатформенность, иначе можно кучу времени потратить на то, что является сложным, windows-ориентированным и никому не нужным.

Раньше я очень часто использовал эвенты, мьютексы, может даже злоупотреблял ими в какой-то степени. Сейчас гораздо реже. Выяснилось, что очень многие вещи можно сделать на крит. секции и циклах ожидания со Sleep :). Может так получается небольшой оверхед, но программа становится проще.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985028
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer и, как минимум, реализовать override-метод Execute.
и, как минимум, переопределить виртуальный метод Execute.


DmSer⚠️ Запущенный поток не завершается при выходе из программыЗавершается
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
procedure _Halt0;
........
{$IF Defined(MSWINDOWS)}
      ExitProcess(ExitCode);
{$ELSEIF Defined(POSIX)}
      __exit(ExitCode);
{$ELSE}
{$MESSAGE ERROR 'Unknown platform'}
{$ENDIF}
      // never arrive hear.
    end;

    InitContext := InitContext.OuterContext^
  end;
end;

Но до выделенной строки дело может не дойти из-за финализации менеджера памяти.

Но я о чем - в Windows процесс живет, пока работает хотя бы один поток процесса, тогда как Delphi принудительно убивает процесс при завершении главного потока

DmSerВаша программа с большой вероятностью будет глючить.Может имеет смысл обойтись без сленга?

DmSerТакже хочу отметить, что при срабатывании таймера не следует обращаться к базе данных из основного потока, лучше это делать из дополнительного потока, разумеется, в отдельном подключении .Если мы говорим о мануале для новичков, то нифига это не разумеется. Если уже зацепил работу с БД, то явно укажи, что делать только так или смотреть документацию к СУБД. Тот же MySQL позволяет расшаривать соединение между потоками, при выполнении определенных условий

DmSerℹ️ Внимание! Если периодическая задача выполняется редко (например, каждые 10 минут), рекомендуется каждый раз (если это не сложно!) для такой задачи создавать новый поток. Вероятно, это лучше, чем часами удерживать дополнительный поток в спящем состоянии (особенно, если вы разрабатываете 32-разрядное Windows-приложение).Чем лучше? Я бы наоборот делал бы обратную рекомендацию. Спящий поток есть не просит, а снаружи лучше управлять одним объектом, чем каждый раз создавать новый. Плюс дополнительное время на инициализацию нового потока


DmSer⚠️ Внимание! Если поток переведён в спящее состояние с помощью функции Sleep, то не существует другого способа выйти из этого состояния кроме истечения указанного временного периодаТак зачем учить плохому? Есть две функции, которые можно использовать исключительно в тестовых приложениях и никогда в реальных Sleep() и Application.ProcessMessages. Новичкам об этих функциях вообще лучше не знать
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985029
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Код: pascal
1.
2.
3.
4.
5.
6.
7.
procedure TForm1.FormDestroy(Sender: TObject);
begin
  // При закрытии программы необходимо завершить работу потока
  // и уничтожить объект потока MyThread
  if MyThread <> nil then
    MyThread.Free;
end;

Ну и в чем великий смысл выделенной строчки? Если
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
  if Self <> nil then
    Destroy;
{$ENDIF}
end;
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985042
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSerЕсли же мы решим объявить для такого потока переменную и будем пытаться с нею работать, то рискуем нарваться на ошибку доступа к памяти «Access Violation», поскольку объект потока может быть уничтожен в любой момент времени.Верно только для случая, когда поток завершается сам
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985065
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSerи, как минимум, реализовать override-метод Execute.
_Vasilisk_и, как минимум, переопределить виртуальный метод Execute.

А точно между этими двумя вариантами выражения есть какая-то разница? На мой взгляд, оба варианта равноценны. Если человек понимает, что такое виртуальный метод, то он также знает что такое override-метод.

_Vasilisk_> Ваша программа с большой вероятностью будет глючить.
Может имеет смысл обойтись без сленга?

Что здесь является сленгом? Слово "глючить"? Вроде нормальный термин для программистов. Да и статья не академическая.



_Vasilisk_> Также хочу отметить, что при срабатывании таймера не следует обращаться к
> базе данных из основного потока, лучше это делать из дополнительного потока,
> разумеется, в отдельном подключении.
Если мы говорим о мануале для новичков, то нифига это не разумеется. Если уже зацепил работу с БД, то явно укажи, что делать только так или смотреть документацию к СУБД. Тот же MySQL позволяет расшаривать соединение между потоками, при выполнении определенных условий

Я согласен. По поводу работы с базой данных обязательно напишу отдельный раздел. Считаю это очень важным. Тем более работа с базами данных - это наиболее популярная область использования Дельфи. Есть большое количество наработок в этой часть. Есть что написать.


_Vasilisk_> ℹ️ Внимание! Если периодическая задача выполняется редко (например,
> каждые 10 минут), рекомендуется каждый раз (если это не сложно!) для
> такой задачи создавать новый поток. Вероятно, это лучше, чем часами
> удерживать дополнительный поток в спящем состоянии (особенно, если
> вы разрабатываете 32-разрядное Windows-приложение).

Чем лучше? Я бы наоборот делал бы обратную рекомендацию. Спящий поток есть не просит, а снаружи лучше управлять одним объектом, чем каждый раз создавать новый. Плюс дополнительное время на инициализацию нового потока

Спящий поток кушает примерно 1,3 МБ адресного пространства (при условии, что 32-разрядная программа запущена на 64-разрядной винде). Это весьма много, ведь 32-разрядной программе доступно всего 2 ГБ под собственные нужны. Стоит лишь открыть TOpenDialog, так на тебе, сразу 300МБ уплыло. Используешь TWebBrowser, так ещё минус 200МБ. А что остаётся?

_Vasilisk_Ну и в чем великий смысл выделенной строчки? Если


Это приём, направленный на повышение читаемости кода. Там же чуть ниже отмечено, для чего так сделано.

_Vasilisk_Верно только для случая, когда поток завершается сам


Именно так!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985067
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
InterlockedIncrement/InterlockedDecrement я бы заменил на кроссплатформенные AtomicIncrement/AtomicDecrement

DmSer
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
  // Создаём поток в спящем состоянии
  FMyThread := TMyThread.Create(True);

  // Запоминаем длину ряда в поле MaxValue
  FMyThread.MaxValue := StrToIntDef(edMaxValue.Text, 0);

  // Пробуждаем поток для выполнения вычислений
  FMyThread.Resume;

Я бы инициализацию MaxValue вынес в конструктор. Чтобы не возникало желания его модифицировать

DmSerНа главной форме находится таймер, который через определённые промежутки времени (каждые 100 мс) считывает из объекта-потока FMyThread свойства CalcResult, CurrValue и ThreadStateInfoИ рискуем получить несогласованные данные.

DmSerprocedure TMyThread.SetThreadStateInfo(const Value: string);
begin
StringProtectSection.Enter; // Входим в режим защиты
FThreadStateInfo := Value;
StringProtectSection.Leave; // Выходим из режима защиты
end;try finally всегда. Даже если внутри одна строчка. Ну и использование одной глобальной критической секции на все - это огромный антипаттерн

DmSer⚠️ Внимание! Если строка (структура, объект, массив) является «константной», т.е. если значение присваивается лишь один раз и больше не меняется, то нет смысла её защищать!Это неверно. При чтении управляемых объектов изменяется счетчик ссылок тынц

DmSerб) освобождается память, занятая старой строкой (с помощью функции менеджера памяти FreeMem).
Память будет освобождена при условии, если старая строка нигде больше не используется, т.е. у неё нулевой счётчик ссылок.Как громоздко.
У строки уменьшается счетчик ссылок. Если он достиг значения 0, то память освобождается

DmSer⚠️ Внимание! Если Вы вводите свои (нестандартные коды сообщений), то необходимо использовать коды не менее WM_USER,WM_APP. Потому, что WM_USER + XXX VCL резервирует для себя. И можно нарваться
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985076
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
он также знает что такое override-метод.
Я впервые слышу такой термин. Я воспринимаю термин "override-метод" как "переопределенный" (в родителе) метод. У нас же в родителе метод абстрактный
DmSer
Спящий поток кушает примерно 1,3 МБ адресного пространства
Где?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
procedure TMyThread.Execute;
begin
  WaitForSingleObject(Handle, INFINITE);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LBase: PROCESS_MEMORY_COUNTERS;
  LInfo1: PROCESS_MEMORY_COUNTERS;
  LInfo2: PROCESS_MEMORY_COUNTERS;
  LInfo3: PROCESS_MEMORY_COUNTERS;
  LStr: string;
begin
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LBase, SizeOf(LBase)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo1, SizeOf(LInfo1)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo2, SizeOf(LInfo2)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo3, SizeOf(LInfo3)));
  LStr := Format('WorkingSet: 1: %d, 2: %d, 3: %d, Total: %d', [
    LInfo1.WorkingSetSize - LBase.WorkingSetSize,
    LInfo2.WorkingSetSize - LInfo1.WorkingSetSize,
    LInfo3.WorkingSetSize - LInfo2.WorkingSetSize,
    LInfo3.WorkingSetSize - LBase.WorkingSetSize
  ]) + Format(#13#10'PageFileSet: 1: %d, 2: %d, 3: %d, Total: %d', [
    LInfo1.PagefileUsage - LBase.PagefileUsage,
    LInfo2.PagefileUsage - LInfo1.PagefileUsage,
    LInfo3.PagefileUsage - LInfo2.PagefileUsage,
    LInfo3.PagefileUsage - LBase.PagefileUsage
  ]);
  ShowMessage(LStr);
end;

Код: plaintext
1.
2.
WorkingSet: 1: 20480, 2: 16384, 3: 32768, Total: 69632
PageFileSet: 1: 81920, 2: 86016, 3: 81920, Total: 249856
Rio 10.3.1. Сборка проекта Debug.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985091
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer В некоторых задачах (например, при математических вычислениях) следует по возможности избегать использования конструкций try..finally и try..except, т.к. они могут нести значительные накладные расходы.Шта?

DmSer
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FList.Free;

  // В списке могут остаться элементы. Это не страшно, поскольку
  // выполняется выход из программы
  EventList.Free;
end;

1. И получить в конце ругань от менеджера памяти об утечках
2. Form1 может оказаться не главной формой и приложение может не завершиться

DmSer Относительный приоритет потока работает только в рамках процесса и никак не влияет на выделение квантов времени потокам, которые работают в других процессах.MSDN с тобой не согласен https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadpriority#remarks The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For example, specifying THREAD_PRIORITY_HIGHEST in a call to SetThreadPriority for a thread of an IDLE_PRIORITY_CLASS process sets the thread's base priority level to 6.

Ну и нет главы о передаче данных в дополнительный поток
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985098
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
DmSer В некоторых задачах (например, при математических вычислениях) следует по возможности избегать использования конструкций try..finally и try..except, т.к. они могут нести значительные накладные расходы.
Шта?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
procedure TForm1.Button1Click(Sender: TObject);
const
  CCount = Round(1e+9);
  CStart = 1e+6;
var
  LStart: Cardinal;
  LClear, LFinally, LExcept: Cardinal;
  Li: Integer;
  LRes: Double;
begin
  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    LRes := Sqrt(LRes);
    LRes := LRes * LRes;
  end;
  LClear := GetTickCount - LStart;

  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    try
      LRes := Sqrt(LRes);
      LRes := LRes * LRes;
    finally

    end;
  end;
  LFinally := GetTickCount - LStart;

  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    try
      LRes := Sqrt(LRes);
      LRes := LRes * LRes;
    except
    end;
  end;
  LExcept := GetTickCount - LStart;

  ShowMessageFmt('Clear: %d, Finally: %d, Except: %d', [LClear, LFinally, LExcept]);
end;

Код: plaintext
Clear: 9844, Finally: 11734, Except: 9922
2 секунды на миллиарде операций стоят того, чтобы отказываться от обработки ошибок?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985134
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_

DmSer
Спящий поток кушает примерно 1,3 МБ адресного пространства
Где?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
procedure TMyThread.Execute;
begin
  WaitForSingleObject(Handle, INFINITE);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LBase: PROCESS_MEMORY_COUNTERS;
  LInfo1: PROCESS_MEMORY_COUNTERS;
  LInfo2: PROCESS_MEMORY_COUNTERS;
  LInfo3: PROCESS_MEMORY_COUNTERS;
  LStr: string;
begin
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LBase, SizeOf(LBase)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo1, SizeOf(LInfo1)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo2, SizeOf(LInfo2)));
  TMyThread.Create(False);
  Win32Check(GetProcessMemoryInfo(GetCurrentProcess, @LInfo3, SizeOf(LInfo3)));
  LStr := Format('WorkingSet: 1: %d, 2: %d, 3: %d, Total: %d', [
    LInfo1.WorkingSetSize - LBase.WorkingSetSize,
    LInfo2.WorkingSetSize - LInfo1.WorkingSetSize,
    LInfo3.WorkingSetSize - LInfo2.WorkingSetSize,
    LInfo3.WorkingSetSize - LBase.WorkingSetSize
  ]) + Format(#13#10'PageFileSet: 1: %d, 2: %d, 3: %d, Total: %d', [
    LInfo1.PagefileUsage - LBase.PagefileUsage,
    LInfo2.PagefileUsage - LInfo1.PagefileUsage,
    LInfo3.PagefileUsage - LInfo2.PagefileUsage,
    LInfo3.PagefileUsage - LBase.PagefileUsage
  ]);
  ShowMessage(LStr);
end;

Код: plaintext
1.
2.
WorkingSet: 1: 20480, 2: 16384, 3: 32768, Total: 69632
PageFileSet: 1: 81920, 2: 86016, 3: 81920, Total: 249856
Rio 10.3.1. Сборка проекта Debug.


Причём тут pagefile? Речь же шла про виртуальное адресное пространство!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985136
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
_Vasilisk_
пропущено...
Шта?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
procedure TForm1.Button1Click(Sender: TObject);
const
  CCount = Round(1e+9);
  CStart = 1e+6;
var
  LStart: Cardinal;
  LClear, LFinally, LExcept: Cardinal;
  Li: Integer;
  LRes: Double;
begin
  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    LRes := Sqrt(LRes);
    LRes := LRes * LRes;
  end;
  LClear := GetTickCount - LStart;

  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    try
      LRes := Sqrt(LRes);
      LRes := LRes * LRes;
    finally

    end;
  end;
  LFinally := GetTickCount - LStart;

  LStart := GetTickCount;
  LRes := CStart;
  for Li := 0 to CCount - 1 do begin
    try
      LRes := Sqrt(LRes);
      LRes := LRes * LRes;
    except
    end;
  end;
  LExcept := GetTickCount - LStart;

  ShowMessageFmt('Clear: %d, Finally: %d, Except: %d', [LClear, LFinally, LExcept]);
end;

Код: plaintext
Clear: 9844, Finally: 11734, Except: 9922
2 секунды на миллиарде операций стоят того, чтобы отказываться от обработки ошибок?


Операция операции рознь. Чем тяжелее операция тем меньше разница. Отказываться от обработки ошибок не нужно. Но и совать её куда ни попадая не следует.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985155
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_DmSerprocedure TMyThread.SetThreadStateInfo(const Value: string);
begin
StringProtectSection.Enter; // Входим в режим защиты
FThreadStateInfo := Value;
StringProtectSection.Leave; // Выходим из режима защиты
end;try finally всегда. Даже если внутри одна строчка. Ну и использование одной глобальной критической секции на все - это огромный антипаттерн


try..finally ради одной безобидной строчки выглядит как-то нерационально. Какой в ней смысл? Кто такое правило ввёл?
Про критическую секцию согласен. Однако в плане обучения я посчитал такой подход проще, удобнее, понятнее. И я не сразу ввожу термин "критическая секция", а постепенно. Иначе у начинающего каша в голове будет и он бросит всё это читать.

_Vasilisk_DmSer Внимание! Если строка (структура, объект, массив) является «константной», т.е. если значение присваивается лишь один раз и больше не меняется, то нет смысла её защищать!Это неверно. При чтении управляемых объектов изменяется счетчик ссылок тынц


Счётчик ссылок может изменяться из разных потоков. Это безопасно в том случае, если строка не меняется.

_Vasilisk_DmSerВнимание! Если Вы вводите свои (нестандартные коды сообщений), то необходимо использовать коды не менее WM_USER,WM_APP. Потому, что WM_USER + XXX VCL резервирует для себя. И можно нарваться

Фантазии какие-то! Назови хоть один случай, где WM_USER+1 не работал!
А ещё огласи, чему равен тот загадочный XXX?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985164
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_

DmSer Относительный приоритет потока работает только в рамках процесса и никак не влияет на выделение квантов времени потокам, которые работают в других процессах.
MSDN с тобой не согласен https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadpriority#remarks The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For example, specifying THREAD_PRIORITY_HIGHEST in a call to SetThreadPriority for a thread of an IDLE_PRIORITY_CLASS process sets the thread's base priority level to 6.


Действительно я накосячил. Исправил. Доработал программу для исследования квантов и приоритетов.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985194
istrebitel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DmSer

Фантазии какие-то! Назови хоть один случай, где WM_USER+1 не работал!
А ещё огласи, чему равен тот загадочный XXX?

http://delphimaster.net/view/1-59239
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985200
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще поправил раздел о приоритетах спорная часть теперь выглядит так:

Обычно программисту нет смысла изменять приоритеты потоков. Приоритет потока никак не влияет на скорость исполнения программного кода. Приоритет потока никак не влияет на размер кванта времени (однако размер кванта времени зависит от того, является ли приложение активным или нет).

:information_source: **Внимание!** У приложения, которое находится на переднем плане, длительность кванта времени увеличивается примерно в 3 раза (это не имеет отношения к базовому приоритету процесса). Одну и ту же вычислительную задачу быстрее (примерно в 3 раза) сможет решить приложение, которое находится на переднем плане. На моих компьютерах с Windows 7 длительность кванта времени у приложений на заднем плане (думаю, что и у служб тоже) составляет 32 мс, а у приложений на переднем плане - 96 мс.

Относительный приоритет потока влияет на выделение процессорного времени как между потоками в рамках одного процесса, так и между потоками различных процессов.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985202
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
istrebitel
DmSer

Фантазии какие-то! Назови хоть один случай, где WM_USER+1 не работал!
А ещё огласи, чему равен тот загадочный XXX?

http://delphimaster.net/view/1-59239


Думаю, что WM_USER+100 нужен при разработке наследников от некоторых компонентов. А лучше изучать исходники и смотреть, какие коды там используются.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985210
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Одну и ту же вычислительную задачу быстрее (примерно в 3 раза) сможет решить приложение, которое находится на переднем плане.


Исправлено:

В том случае, если два приложения будут привязаны к одному ядру процессора, то одну и ту же вычислительную задачу быстрее (примерно в 3 раза) сможет решить приложение, которое находится на переднем плане.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985217
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,

От настроек зависит. На серверных виндах приоритет у фоновых задач.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985282
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
DmSer,

От настроек зависит. На серверных виндах приоритет у фоновых задач.


Как-то странно это работает. Поставил приоритет для служб в фоновом режиме, теперь квант у обычных программ резко подрос и стал около 195 мс. Причем теперь он у всех одинаковый и не зависит от того, на переднем плане программа или на заднем плане.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985284
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,

Да, про увеличение размера кванта написано у Русиновича, кажется (Внутреннее устройство Windows).
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985295
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, величина самого длинного кванта на Windows 2000 всего 36.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985343
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Счётчик ссылок может изменяться из разных потоков. Это безопасно в том случае, если строка не меняется.
Счетчик ссылок может стать нулем

Ладно. Я все понял. Твой подход: "зачем делать правильно если в конкретном частном случае работает и так?".

Только программа имеет тенденцию развиваться и мне проще изначально писать правильно, чем потом выискивать места, где нужно что-то поправить
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985370
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
DmSer
Счётчик ссылок может изменяться из разных потоков. Это безопасно в том случае, если строка не меняется.
Счетчик ссылок может стать нулем


Речь идёт о "константной" строке, значение которой присваивается один раз и больше не меняется.
Счётчик станет нулём в том случае, если строка никому больше не нужна. В этом случае строка будет уничтожена, память освободится. Никаких проблем с многопоточным доступом тут нет. Конечно, можно на всякий случай каждую строчку кода защищать критической секцией и для каждой строки на всякий случай вызывать UniqueString. Но зачем?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985425
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
_Vasilisk_
пропущено...
Счетчик ссылок может стать нулем


Речь идёт о "константной" строке, значение которой присваивается один раз и больше не меняется.
Счётчик станет нулём в том случае, если строка никому больше не нужна. В этом случае строка будет уничтожена, память освободится. Никаких проблем с многопоточным доступом тут нет. Конечно, можно на всякий случай каждую строчку кода защищать критической секцией и для каждой строки на всякий случай вызывать UniqueString. Но зачем?


Сколько интересных граблей необходимо помнить и обходить, если вместо подходящих инструментов и подходов использовать базовые...

На моей памяти уже несколько лет не было случая, чтобы что-то блокировать, кроме очередей.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39985714
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавлена информация о threadvar и немного о UniGui.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986194
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986248
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.

Только с некой оговоркой, как у меня. Синхронизация с главным потоком происходит через посредника - отдельного потока, которым пользуются все остальные. Так я избавляюсь от ожидания.

Сказал посреднику, что хочешь сообщить главному и дальше пошел работать.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986306
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.
и для VCL я это советую - 22162612
и на это есть много причин
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986397
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)
и для VCL я это советую

И не знаешь, кого слушать :)

Это как с Application.ProcessMessages - все кричат, что его применение - моветон и чревато страшными багами, а на деле - вероятность можно на пальцах посчитать
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986400
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman
Так я избавляюсь от ожидания.

сложно это все. Я проще поступаю: если надо дождаться в доп.потоке реакции от главного - делаю Synchronize/SendMessage, если пофиг - Queue/PostMessage :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986409
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Докесли надо дождаться в доп.потоке реакции от главного - делаю Synchronize/SendMessage

В моё время Synchronize не принимал параметры и не позволял вернуть значение, приходилось
всё делать через левые переменные.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986437
Vizit0r
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
kealon(Ruslan)
и для VCL я это советую

И не знаешь, кого слушать :)

Это как с Application.ProcessMessages - все кричат, что его применение - моветон и чревато страшными багами, а на деле - вероятность можно на пальцах посчитать


а на деле вопрос получения трудновыловимых багов от Application.ProcessMessages в случае многопоточного приложения - это вопрос времени.
А первый раз, не зная куда копать - можно очень долго искать причину.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986465
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Vizit0r
а на деле вопрос получения трудновыловимых багов от Application.ProcessMessages в случае многопоточного приложения - это вопрос времени.

да расслабьтесь, я его втыкаю только в тестовых приложениях :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986482
Vizit0r
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док,
я из своего опыта просто делюсь...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986534
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Vizit0r
Док
пропущено...

И не знаешь, кого слушать :)

Это как с Application.ProcessMessages - все кричат, что его применение - моветон и чревато страшными багами, а на деле - вероятность можно на пальцах посчитать


а на деле вопрос получения трудновыловимых багов от Application.ProcessMessages в случае многопоточного приложения - это вопрос времени.
А первый раз, не зная куда копать - можно очень долго искать причину.


Неоднократно сталкивался с проблемами, которые проявлялись при использовании Application.ProcessMessages. Поэтому в "учебнике" никому советовать использовать Application.ProcessMessages не буду.

Например, были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока. Получается фигня. Лучше модальное окно показать с какой-нибудь анимацией и закрывать его при окончании работы потока. Причем модальное окно можно делать невидимым первые 5 секунд. Позже я опишу этот приём в "учебнике".
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986535
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока
Нафига, если есть Timer и Event-ы?

ProcessMessages нужен для того что бы интерфейс не залипал при длительной работе в основном потоке. Да и то надо в уме держать возможные побочные эффекты, и например, отключать ненужные возможности по вводу данных в GUI.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986579
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat
DmSer
были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока
Нафига, если есть Timer и Event-ы?

ProcessMessages нужен для того что бы интерфейс не залипал при длительной работе в основном потоке. Да и то надо в уме держать возможные побочные эффекты, и например, отключать ненужные возможности по вводу данных в GUI.


Я уже как-то рассказывал, в этом году обнаружил код в нашем ПО, в котором запускался доп. поток для формирования отчета и выполнялось ожидание окончания формирования отчёта с помощью цикла:
Код: pascal
1.
2.
3.
4.
5.
while not RepThread.Ready do
begin
  Sleep(10);
  Application.ProcessMessages;
end; 



В случае, если сервер отчётов находился не в локальной сети, а где-то в сети интернет, то метод ProcessMessages не возвращал управление (но GUI при этом обновлялся). Детально не разбирался, почему так. Просто реализовал ожидание с помощью модальной формы и теперь никаких зависаний нет.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986595
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
rgreat
пропущено...
Нафига, если есть Timer и Event-ы?

ProcessMessages нужен для того что бы интерфейс не залипал при длительной работе в основном потоке. Да и то надо в уме держать возможные побочные эффекты, и например, отключать ненужные возможности по вводу данных в GUI.


Я уже как-то рассказывал, в этом году обнаружил код в нашем ПО, в котором запускался доп. поток для формирования отчета и выполнялось ожидание окончания формирования отчёта с помощью цикла:
Код: pascal
1.
2.
3.
4.
5.
while not RepThread.Ready do
begin
  Sleep(10);
  Application.ProcessMessages;
end; 




В случае, если сервер отчётов находился не в локальной сети, а где-то в сети интернет, то метод ProcessMessages не возвращал управление (но GUI при этом обновлялся). Детально не разбирался, почему так. Просто реализовал ожидание с помощью модальной формы и теперь никаких зависаний нет.

О, господи.
Мне кажется, правильнее было бы реализовать "ожидание" убрав формирование отчета из доп потока в главный. Раз уж зачем-то нужно "ожидание".
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986603
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock

Мне кажется, правильнее было бы реализовать "ожидание" убрав формирование отчета из доп потока в главный. Раз уж зачем-то нужно "ожидание".


В нашем случае ПО управляет ещё кучей устройств, главный поток дёргается постоянно, поэтому мы не можем надолго его блокировать.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986831
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
запускался доп. поток для формирования отчета и выполнялось ожидание окончания формирования отчёта с помощью цикла:

а в доп.потоке -то оно зачем?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986846
Фотография roschinspb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Hi
Во-первых, хочу по-приветствовать идею написания книги, выразить моральную поддержку и пожелать творческих успехов.

Во-вторых, позволь внести пару предложений.
В разделе 1.2. надо как-то более сжато выделить проблемы и требования к многопоточным приложениям. Что-то типа этого:
1. Библиотеки графических компонентов (как VCL так и FMX) способны корректно работать только в основном потоке, обращение к ним напрямую из любых других потоков недопустимо (как допустимо будет сказано ниже).
2. Обращение к данным внутри потока напрямую также недопустимо, так как в любой случайный момент времени данные могут быть еще полностью не сформированы, память не выделена, или уже уничтожена.
3. Многие не графические компоненты скрыто взаимодействуют между собой и графическим интерфейсом приводя к нарушениям требований 1 и 2. Например: TSQLConnection, TSQLDataSet, TDataSource и TDBEdit.
4. Требования из предыдущих пунктов ни как не контролируется средой разработки и требует особой внимательности разработчика. При этом ошибки носят вероятностный характер. Зачастую возможность появления ошибки зависит от скорости работы процессора, заполненности памяти, скорости работы сети и т.п.
5. Даже в случае правильной и безошибочной работы приложения не всегда возможна подлинная многозадачность. Например: выполнение длительных запросов в рамках одной сессий Oracle не может выполняться параллельно, т.е. запустив выполнение длительного запроса в отдельном потоке пользователь тем не менее всё равно не сможет полноценно работать с данными.

Когда вы собираетесь выносить часть кода в отдельный поток следует обратить внимание на следующие моменты:
1. Необходимо максимально сократить доступ к графическому интерфейсу, в идеале совсем исключить.
2. Необходимо максимально изолировать код внутри потока. Например: создаем модуль данных, подключаемся к БД, выполняем запрос, записываем результаты выполнения, разрушаем модуль данных.
3. Обязательно надо убедиться в потокозащищенности используемых в потоке компонентов. Причем декларируемая потокозащищенность не всегда соответствует действительности.
4. Следует убедиться в наличие достаточных человеческих ресурсов. Отладка будет на порядок сложнее, подумайте еще раз стоит ли игра свеч? Может целесообразней вынести долгое вычисление в отдельное приложение? Нужна ли действительно постоянная активность графического интерфейса, или достаточно простого окна ожидания?

Возможно стоит вынести код не в отдельный поток а в отдельное небольшое консольное приложение.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986862
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
roschinspb,
Спасибо за предложения! Я их проанализирую и постараюсь отразить в статье.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986899
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
roschinspb,

Сереж, у тебя же на "народе" небольшая статья была с примерами потоков...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986945
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
roschinspb,

автор4. Следует убедиться в наличие достаточных человеческих ресурсов. Отладка будет на порядок сложнее, подумайте еще раз стоит ли игра свеч? Может целесообразней вынести долгое вычисление в отдельное приложение? Нужна ли действительно постоянная активность графического интерфейса, или достаточно простого окна ожидания?


я бы не сказал, что так уж сложно и на порядок. достаточно придерживаться известных принципов: не лезть к vcl и к расшаренным ресурсам и в 99% случаев всё сразу же заработает. невизуальные компоненты, имеющие проблемы в многопоточке - скорее исключение.
долгие вычисления как правило предполагают много данных и гонять данные между приложениями в обе стороны - то еще удовольствие
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986952
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon,

не так уж и сложно гонять.

доп процесс полезен если используются сторонние библиотеки, которые могут привести к зависанию программы. пришлось так делать когда использовал bass что бы писать интернет радио...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39986972
Vizit0r
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Zelius
makhaon,

не так уж и сложно гонять.

доп процесс полезен если используются сторонние библиотеки, которые могут привести к зависанию программы. пришлось так делать когда использовал bass что бы писать интернет радио...


это скорее исключение.
А в целом - гораздо полезнее разобраться с потоками, чем с межпроцессным взаимодействием.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987001
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Vizit0r,

полезнее знать что делать, когда программа виснет в чужой dll и никакие потоки не спасают, т.к. их не перезапустить...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987022
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Zelius
makhaon,

не так уж и сложно гонять.

доп процесс полезен если используются сторонние библиотеки, которые могут привести к зависанию программы. пришлось так делать когда использовал bass что бы писать интернет радио...


К сожалению, межпроцессное взаимодействие это не та задача, которая возникает у большинства Delphi-программистов каждый день. В RTL, если не ошибаюсь, нет практически ничего готового в помощь для решения этой задачи (я не говорю о взаимодействии по TCP или через COM, тут как раз более менее всё необходимое имеется). Если возникает задача организовать взаимодействие между процессами в рамках одного компьютера, то, думаю, каждый Delphi-программист вынужден мастерить свой велосипед.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987026
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
roschinspb,

а где предложение про Окно, отображающее ход выполне­ния длительной операции ? :)
Было бы уместным!
С ним кстати не было проблем/сбоев? Работает во всех версиях Delphi?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987029
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так или иначе, "учебник" в первую очередь о том, как научиться многопоточному программированию в Delphi (в идеале, для решения различных задач, где уместна многопоточность), а не о том, как решать различные задачи, не прибегая к многопоточному программированию.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987080
Vizit0r
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Zelius
Vizit0r,

полезнее знать что делать, когда программа виснет в чужой dll и никакие потоки не спасают, т.к. их не перезапустить...


это уже сильно частные случаи, на самом деле.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987164
Фотография roschinspb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
roschinspb,

а где предложение про Окно, отображающее ход выполне­ния длительной операции ? :)
Было бы уместным!
С ним кстати не было проблем/сбоев? Работает во всех версиях Delphi?

Для начинающих пример сложноват. Это скорее для второго тома. Многопоточное программирование для тех, кто бросает. 😁. Вообще на сайте не последняя версия. Последняя с исправлениями для 64 бит погибла вместе с винчестером. Когдато яя её кому-то выслал, может где и есть еще.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987213
Фотография roschinspb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
невизуальные компоненты, имеющие проблемы в многопоточке - скорее исключение

Я не знаю какая у тебя предметная область... у меня всякие клиент-серверные приложения, весьма крупные. И вот сколько бы контор не сменил почти во всех натыкался на решения " а не выполнить ли мне долгие запросы в отдельном потоке ". И использовать какраз компоненты имеющие проблемы в многопоточке и которые обращаются к графическому интерфейсу скрыто от глаз молодого бойца.
Описание проблемы в терминах тестировщика типа: " вот чето у нас всё работает, а у клиентов... у некоторых... иногда зависает в непонятных местах ".
Код хорошо характеризует высказывание одного патологоанатома:
В нашем морге последними словами 40% клиентов было "Гляди посоны как я могу!", а половина клиентов последнее что сказала "Не, дай я покажу как надо!".
Почти всегда исправление заключается в тупом переносе кода в основной поток. Прогрессбар можно перерисовать и repaint-ом, а обеспечивать реальную параллельную работу пользователя и так не требовалось.

makhaon

долгие вычисления как правило предполагают много данных и гонять данные между приложениями в обе стороны - то еще удовольствие
А мне вот кажется что вычислительные задачи сводятся к "Получить данные из файла" -> "обработать" -> "сохранить результаты в файл". Вcё просто, ни каких межпроцессных обменов, для особых эстетов разве что процент выполнения можно прикрутить.

P.S. Я не призываю отказаться от тредов вообще и не надо меня убеждать в том что иногда они нужны. Я просто пытаюсь избавить от лишних проблем начинающих программеров и тех кто потом за ними будет код чистить.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987286
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Так вот кто гуглу насоветовал про процессы, так что теперь хром плодит свои копии интенсивней, чем зерглинги вылупляются!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987327
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal
теперь хром плодит свои копии интенсивней, чем зерглинги вылупляются!

146%!
И на старых машинах иногда завешивает проц вусмерть.

roschinspb
Прогрессбар можно перерисовать и repaint-ом

если только в таймере. Интересно, сколько таймеров можно запустить без заметного вреда для софтины?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987333
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
мне кажется эта статья описывает многопоточность достаточно хорошо, многое оттуда взять можно https://forum.vingrad.ru/topic-60076.html
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987371
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cptngrb
мне кажется эта статья описывает многопоточность достаточно хорошо, многое оттуда взять можно https://forum.vingrad.ru/topic-60076.html


Да, я с нею знакомился. Она не для начинающих. Писалась в те времена, когда программирование было уделом гениев. Очень тяжело усваивается. Думаю, мало кто осилит дочитать более 30% (до БАБ врядли дело дойдет :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987639
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Zelius
...
пришлось так делать когда использовал bass что бы писать интернет радио...
Если не секрет, какой протокол от сервера к клиенту? Какой-нибудь HLS или Icecast?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987877
Фотография roschinspb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док
. Интересно, сколько таймеров можно запустить без заметного вреда для софтины?
много. В fix чуть менее чем у всех контролов есть анимация, а она содержит таймер.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987893
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавлен раздел планирование потоков
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987959
ART-CODE
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987962
ART-CODE
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spinlock
https://ru.wikipedia.org/wiki/Спин-блокировка

I/O Completion Ports
https://docs.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports
------
Не всем, и не всегда нужна кроссплатформенность.
Бывает, что важнее выжать по-максимуму из возможностей ОС и процессора.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39987979
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62,

Использовал чтото высокоуровневое, просто урл передавал, под капот потока не смотрел
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39989478
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док,
зы. на скруле всегда так, как только тема исчерпывается, начинается оффтоп

Рано! Кучу материалов изучаю по многопоточности. Что-нибудь получится! :)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39989804
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
cptngrb
мне кажется эта статья описывает многопоточность достаточно хорошо, многое оттуда взять можно https://forum.vingrad.ru/topic-60076.html


Да, я с нею знакомился. Она не для начинающих. Писалась в те времена, когда программирование было уделом гениев. Очень тяжело усваивается. Думаю, мало кто осилит дочитать более 30% (до БАБ врядли дело дойдет :)

На мой взгляд неплохо или просто хорошо :) написано у Пачеко и Тексейры https://www.for-stydents.ru/informatika/delphi/uchebniki/delphi-5-rukovodstvo-razrabotchika-tom-1-osnovnye-metody-i-tehnologii-programmirovaniya.html Хотя книжка старая, 2000 года.
Глава 11 "Создание многопоточных приложений". По-моему довольно простое, понятное изложение, при этом затронуты разные темы, в том числе многопоточный доступ к БД, графика.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990039
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Переработан раздел Планирование потоков

Пришлось убрать раздел "Роль кэшей процессора", т.к. выяснилось, что кэши процессора практически не играют никакой роли в планировании потоков и переключении контекста, а парить читателю мозги лишней информацией я не хочу.
Кто в теме разбирается, посмотрите на предмет того, чтобы не было дезинформации.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990047
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,

warning Внимание! Согласно официальной документации, в секции threadvar нельзя объявлять переменные некоторых типов, в том числе: Pointer, Function, а также типы, работающие по принципу copy-on-write, например string.

Где это такие глупости написаны??? Официальная дока:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Variables_(Delphi)#Thread-local_Variables Thread-variable declarations:

cannot occur within a procedure or function.
cannot include initializations.
cannot specify the absolute directive.

Dynamic variables that are ordinarily managed by the compiler (long strings, wide strings, dynamic arrays, variants, and interfaces) can be declared with threadvar, but the compiler does not automatically free the heap-allocated memory created by each thread of execution. If you use these data types in thread variables, it is your responsibility to dispose of their memory from within the thread, before the thread terminates.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990057
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
DmSer,

warning Внимание! Согласно официальной документации, в секции threadvar нельзя объявлять переменные некоторых типов, в том числе: Pointer, Function, а также типы, работающие по принципу copy-on-write, например string.


Где это такие глупости написаны??? Официальная дока:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Variables_(Delphi)#Thread-local_Variables Thread-variable declarations:

cannot occur within a procedure or function.
cannot include initializations.
cannot specify the absolute directive.

Dynamic variables that are ordinarily managed by the compiler (long strings, wide strings, dynamic arrays, variants, and interfaces) can be declared with threadvar, but the compiler does not automatically free the heap-allocated memory created by each thread of execution. If you use these data types in thread variables, it is your responsibility to dispose of their memory from within the thread, before the thread terminates.

Я взял это несколько недель назад из их официальной документации, по той же ссылке. Видимо, уже успели поменять.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990058
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Я взял это несколько недель назад из их официальной документации. Видимо, уже успели поменять.

Сходи по ссылке и посмотри дату последней модификации страницы.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990061
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дока от Delphi 2006:
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990074
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey,
Такой значит у них бардак в документации. Хорошо что заметили и поправили.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990126
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Измерил, как зависит количество запущенных потоков на производительность. Запускал 100000 потоков (64-битный компилятор), в каждом лишь такой код:

Код: pascal
1.
2.
while not Terminated do 
  Sleep(30000)



Т.е. потоки тупо ничего не делают.

Измерял число операций на 4-х ядрах до запуска и после запуска этих потоков. Выяснилось, что падение производительности составляет 6%. Хотя я думал, что будет намного хуже.
Замеры делал с помощью "CalcTimeQuant.exe". Выяснилось, что 3 из 4-х ядер вообще не замечают этих спящих потоков и выдают максимальную производительность. Производительность падает грубо говоря только на одном ядре (видимо на нем и работает планировщик).
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990151
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Kazantsev Alexey,
Такой значит у них бардак в документации. Хорошо что заметили и поправили.


Ошибся. Ссылка не та все-таки. Использовал эту ссылку
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990170
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Переработан раздел Планирование потоков

Пришлось убрать раздел "Роль кэшей процессора", т.к. выяснилось, что кэши процессора практически не играют никакой роли в планировании потоков и переключении контекста, а парить читателю мозги лишней информацией я не хочу.
Кто в теме разбирается, посмотрите на предмет того, чтобы не было дезинформации.


Последний эксперимент дал новые идеи :)
Я ещё раз переработал этот раздел!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990199
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer,
авторЯ предполагаю, что логика обработки прерывания от системного таймера примерно такая:

системный таймер подаёт сигнал прерывания на все ядра процессора;
приостанавливается работа всех выполняемых потоков на всех ядрах процессора;
осуществляется запуск системного планировщика на одном из ядер процессора (Sheduler Core);
Руссинович и Соломон пишут вот тут https://www.microsoftpressstore.com/articles/article.aspx?p=2233328&seqNum=7 ,
авторTo make thread-scheduling decisions, the kernel maintains a set of data structures known collectively as the dispatcher database, illustrated in Figure 5-15. The dispatcher database keeps track of which threads are waiting to execute and which processors are executing which threads.

To improve scalability, including thread-dispatching concurrency, Windows multiprocessor systems have per-processor dispatcher ready queues, as illustrated in Figure 5-15. In this way each CPU can check its own ready queues for the next thread to run without having to lock the systemwide ready queues.
(Versions of Windows before Windows Server 2003 used a global database).
что, начиная с Windows server 2003 данные об очереди готовых к исполнению потоков у каждого процессора своя, так что они могут проверять каждый свою очередь, не блокируя очереди на уровне всей системы.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990219
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62
DmSer,
авторЯ предполагаю, что логика обработки прерывания от системного таймера примерно такая:

системный таймер подаёт сигнал прерывания на все ядра процессора;
приостанавливается работа всех выполняемых потоков на всех ядрах процессора;
осуществляется запуск системного планировщика на одном из ядер процессора (Sheduler Core);

Руссинович и Соломон пишут вот тут https://www.microsoftpressstore.com/articles/article.aspx?p=2233328&seqNum=7 ,
авторTo make thread-scheduling decisions, the kernel maintains a set of data structures known collectively as the dispatcher database, illustrated in Figure 5-15. The dispatcher database keeps track of which threads are waiting to execute and which processors are executing which threads.

To improve scalability, including thread-dispatching concurrency, Windows multiprocessor systems have per-processor dispatcher ready queues, as illustrated in Figure 5-15. In this way each CPU can check its own ready queues for the next thread to run without having to lock the systemwide ready queues.
(Versions of Windows before Windows Server 2003 used a global database).
что, начиная с Windows server 2003 данные об очереди готовых к исполнению потоков у каждого процессора своя, так что они могут проверять каждый свою очередь, не блокируя очереди на уровне всей системы.

Классная статья! По ней убеждаюсь, что информация в моей статье в разделе "планирование потоков" более-менее корректная.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39990232
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Классная статья! По ней убеждаюсь, что информация в моей статье в разделе "планирование потоков" более-менее корректная.

Просто у этих ребят было добро на публикацию "инсайдерской" инфы от MыSы.

Вот ты её же по кусочкам раньше и насобирал.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995674
didgik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А я вот не понял п4.1
Зачем Sleep() обертывать в WaitTimeout ?
авторwarning Внимание! Если поток переведён в спящее состояние с помощью функции Sleep, то не существует другого способа выйти из этого состояния кроме истечения указанного временного периода.
И что тогда использовать вместо Sleep?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995693
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
didgik
И что тогда использовать вместо Sleep?

Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995708
didgik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman
didgik
И что тогда использовать вместо Sleep?

Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне.


Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995725
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
didgik
А я вот не понял п4.1
Зачем Sleep() обертывать в WaitTimeout ?


Можно и не обертывать. В данном случае поведение программы от этого не изменится. Однако действие по ожиданию таймаута может быть более сложным, чем просто вызвать Sleep. В этом случае разумнее вынести код в отдельную функцию. В дальнейшем можно улучшить код в данной функции, не переделывая все места, из которых эта функция вызывается.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995727
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
didgik

И что тогда использовать вместо Sleep?


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995731
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995734
didgik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
didgik

И что тогда использовать вместо Sleep?


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX

я, кстати, не нашел ThreadWaitTimeout в 2007.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995745
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мимопроходящий

04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй


Оверхед меньше по сравнению с sleep(10) в цикле.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995753
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
didgik
DmSer
пропущено...


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX

я, кстати, не нашел ThreadWaitTimeout в 2007.


Там её нет. Искать нужно там же где статья.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995786
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
didgik
wadman
пропущено...

Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне.


Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал?
Из любого потока.
Посылать сигнал только тогда, когда нужно. Будить таким образом поток, если нужно.
А в Thread.Destroy сделать Terminate и SetEvent. А в потоке после ожидания проверять на Terminated.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #39995965
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Мимопроходящий

04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй


Оверхед меньше по сравнению с sleep(10) в цикле.


Помимо меньшего оверхеда также следует отметить время реакции.

Поток, остановленный по команде Sleep, может возобновить работу только после срабатывания системного таймера. А по умолчанию системный таймер срабатывает примерно раз в 16 миллисекунд.

При ожидании на WaitForXXXXX возобновление работы происходит намного оперативнее.

Идеальный случай, когда в момент вызова SetEvent / ReleaseMutex у планировщика есть возможность запустить ожидающий поток на том же ядре и отсутствуют другие желающие, кому требуется это же ядро. Тогда планировщик запускает ожидающий поток немедленно, не прибегая к системному таймеру или к механизму асинхронного вызова APC. На всё про всё уходит порядка 6 микросекунд (железо не самое мощное).
Однако такое происходит редко, чаще планировщик запускает ожидающий поток с использованием механизма APC (с программным прерыванием), в этом случае уходит от 20 до 50 микросекунд (на моих тестах).
Худший случай, когда механизм APC не смог запустить ожидаемый поток (мог вклиниться поток с более высоким приоритетом), тогда запуск ожидающего потока будет запланирован уже по событию системного таймера.
Как-то так оно работает (в моём понимании).
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40021250
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
За последнее время:
1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads
2. Добавлен раздел "Основные объекты синхронизации в Windows"
3. Добавлен раздел "7.1 Главный поток управляет работой дополнительного потока с помощью объекта "Event" (событие)" и к нему пример FastStopThread
4. Добавлен пример SimpleLogger, который очень наглядно демонстрирует преимущество использования доп. потока при записи в лог-файл (соответствующее описание к данному примеру пока отсутствует).
5. Исправлено несколько замечаний, в том числе большая часть замечаний от _Vasilisk_
6. Учтены некоторые предложения
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40021565
Sapersky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DmSer
1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads
Про псевдо-многопоточность я бы ещё написал, что можно прятать умеренные по времени задержки (до 0.5 с) в OnIdle. OnIdle срабатывает, когда нет новых сообщений окну, в частности когда пользователь перестаёт тыкать в клавиатуру/мышь. То есть можно отложить относительно длительные действия на периоды неактивности пользователя.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40023723
Volk65
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40023762
white_nigger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Volk65
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.
А классику "Multithreading – The Delphi Way" уже прочитал? )) Имхо лучшее для "не новичка"
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40033612
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Volk65
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.


Спасибо, буду рад, если мои труды принесут для кого-то пользу!

Добавлены следующие новые разделы:

7.2 Использование объекта "Event" для разработки потока логгирования ...

7.3 Пара слов об объекте "Mutex" ...

7.4 Пара слов об объекте "Semaphore" ...

7.5 Критическая секция и монитор ...

7.6 Механизм синхронизации "много читателей и один писатель" (MREW) ...

8. Обработка исключений в дополнительных потоках ...
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40034473
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавлен пример использования TThreadedQueue
https://github.com/loginov-dmitry/multithread/tree/master/ExQueue/ExThreadedQueue

Комментарии есть в исходниках примера. В статье пока нет.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40050547
destroyer86
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DmSer, а можете добавить примеров с описанием где и как можно применять CreateThread.
Например как решение в топике: https://stackoverflow.com/questions/25949391/simple-tcp-connect-timeout-wrapper-in-delphi
Либо можно сделать что-то аналогичное с помощью TThread?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40059641
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавлены новые разделы:

9. Передача данных в дополнительный поток ...

9.1 Использование обычного списка (TList, TStringList, TThreadList) и периодический контроль списка ...

9.2 Использование обычного списка (TList, TStringList, TThreadList) и объекта Event ...

9.3 Использование очереди TThreadedQueue<T> (множество producer-потоков и один consumer-поток) ...

12. Работа с базой данных из дополнительного потока ...

13. Проблемы, возникающие при создании большого количество потоков ...

В частности, содержимое п. 13:

1. Ограниченность адресного пространства. Сейчас практически никто не использует 32-разрядную ОС Windows. Если мы скомпилируем своё приложение в 32-битном режиме (с размером стека по умолчанию 1 МБ), запустим его в 64-битной ОС Windows и попытаемся создать 2000 потоков, то получим ошибку. Система не в состоянии создать более 1650 потоков. На каждый созданный поток Windows выделяет 1 МБ виртуальной памяти для 32-битного стека и 256 КБ виртуальной памяти для 64-битного стека (его Windows создаёт и поддерживает автоматически для обеспечения возможности работы 32-битных программ в 64-битной ОС). Насколько я понимаю, на размер 64-битного стека мы влиять не можем, но, если уменьшим размер виртуальной памяти под 32-битный стек (это можно сделать в окне Project / Options / Linker / Max stack size), то можем значительно увеличить максимальное количество потоков в приложении. При этом необходимо воздержаться от объявления локальных статических массивов с большим числом элементов. Данная проблема (с ограниченностью адресного пространства) актуальна только для 32-битных приложений. Если вы компилируете 64-битное приложение, то данной проблемы не существует.

2. Ограниченность физической памяти. Информация актуальна для 64-битной Windows и стандартного менеджера памяти (либо FastMM4). Один поток в 32-битной программе занимаем минимум 88 КБ ОЗУ. В 64-битной программе поток весит меньше - минимум 52 КБ ОЗУ (очевидно, экономия достигается за счёт того, что используется только один стек - 64-битный). Это значение не зависит от объёма виртуальной памяти, выделенной под стек. Учитывайте это, если планируете создавать огромное количество потоков!

3. Использование функции WinAPI-функции Sleep либо WaitForXXX для организации задержек в бесконечном цикле. Очень простое решение - реализовать в дополнительном потоке бесконечный цикл, периодически проверять значение какого-то флага (либо элемента в очереди), в зависимости от значения флага выполнять какое-либо действие, после чего переводить поток в спящий режим с помощью Sleep либо WaitForXXX. Если вы укажете время ожидания 1000 мс (или больше), то нет проблем (в том смысле, что нагрузка на процессор будет минимальной - примерно 50000 тактов в секунду при паузе в 1 секунду). Однако если Вы будете проверять значение флага каждые 10 миллисекунд, то нагрузка на процессор будет уже существенной - 2500000 тактов в секунду будет тратиться только на работу Sleep(10). Если у вас запущено 1000 таких потоков и каждый расходует 2500000 тактов в секунду, то будет обеспечена 100% загрузка одного ядра процессора (либо эта загрузка будет размазана по нескольким ядрам). Т.е. ваши 1000 потоков ещё не делают ничего полезного, но уже грузят процессор по полной программе! :)
Для того, чтобы такой проблемы не было, не рекомендуется использовать Sleep либо WaitForXXX с маленькой задержкой. Гораздо лучше использовать WaitForXXX с большой задержкой (в том числе, INFINITY), а при изменении значения флага следует переводить объект ядра, который ожидает функция WaitForXXX, в сигнальное состояние. В этом случае потоки не будут тратить на контроль состояния флага практически никаких ресурсов процессора!

4. Использование TIdTCPServer для поддержания большого количества сетевых подключений. В древних версиях Indy10 вызовы Socket.ReadXXX приводили к высокой загрузке процессора. Приходилось их "разбавлять" с помощью Sleep(1) для снижения нагрузки на процессор. Такая же ситуация была с методом Socket.CheckForDataOnSource. Более того, раньше метод Socket.CheckForDataOnSource ещё и глючил - не возвращал управление, пока не закончится время ожидания, даже если пришли данные (поэтому приходилось его вызывать с минимальным таймаутом). Указанные проблемы приводили к созданию огромной нагрузке на процессор при большом количестве сетевых подключений.
На данный момент в Indy10 эти проблемы решены. Актуальную версию Indy10 можно скачать с github, при этом она обычно работает c любой версией Delphi. Теперь методы ReadXXX и CheckForDataOnSource не создают никакой нагрузки на процессор и возвращают управление немедленно при появлении данных в сокете (в течение 100 микросекунд, если сервер и клиент запущены на одном компьютере).
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40059667
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40059688
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев.


Я его не использовал, поэтому не стал про него ничего сочинять. Нужны какие-то удачные примеры использования. Технически это тот же Synchronize, только метод подсовывается снаружи, т.е. поток не привязан к какой-то конкретной форме.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40075768
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Скорректирована информация по использованию TIdTCPServer ( ссылка )

Теперь информация изложена в следующем виде:

4. Неправильное использование компонента `TIdTCPServer`. При разработке TCP-серверов Delphi-программисты чаще всего используют компонент TIdTCPServer. При правильном использовании данный компонент может держать до 50000 подключений (существуют реальные примеры с таким количеством подключений). Разумеется, для этого программа должна быть 64-битной. Для поддержки 50000 подключений будет создано 50000 потоков и выделено около 3 ГБ ОЗУ, что весьма затратно. При таком количестве потоков ни в коем случае не должно быть циклов, в которых выполняется проверка чего-либо каждые 10 мс. Значение `Socket.ReadTimeout` должно быть не менее 10000 (10 секунд). При использовании `Socket.CheckForDataOnSource` для ожидания приёма данных от клиента также желательно использовать значение не менее 10000.
**Внимание!** Перед каждым вызовом `Socket.CheckForDataOnSource` необходима проверка `if Socket.InputBuffer.Size = 0 then`, что обусловлено особенностями реализации метода `CheckForDataOnSource`. Если в буфере есть данные, то выполнять вызов `Socket.CheckForDataOnSource` не следует!

**Информация!** Сами по себе данные в буфере `Socket.InputBuffer` появиться не могут. Появляются они там в следующих случаях:
а) в контексте вызова метода `Socket.ReadXXX`,
б) в контексте вызова метода `Socket.CheckForDataOnSource`,
в) в момент подключения клиента к серверу, если клиент сразу же передал данные на сервер.

**Информация!** На практике Delphi-программисту очень редко приходится разрабатывать TCP-сервер, способный держать 50000 соединений. Всё зависит от того, что именно делает TCP-сервер. Если он не выполняет какой-то особой обработки, а просто возвращает в ответ на запрос клиента текущее время (или иную информацию, которую не нужно запрашивать из базы данных или получать в результате сложных вычислений), то проблем никаких нет. Однако, если на каждый запрос приходится выполнять обращение к базе данных или производить сложные вычисления, то ресурсы сервера могут закончиться гораздо раньше (например, на 1000 соединений). В связи с этим рекомендую минимизировать количество обращений к базе данных и стараться держать всю необходимую информацию в памяти TCP-сервера, периодически обновляя её в фоновом потоке.

**Внимание!** Не рекомендую использовать `TIdTCPServer` для решения задачи транзита данных. Данная задача отличается тем, что TCP-сервер не выполняет практически никакой обработки данных, а лишь передаёт клиенту "Б" данные, принятые от клиента "А" (и обратно). Если таких клиентов ("А" и "Б") будет 50000, то программа будет использовать около 3 ГБ ОЗУ. Загрузка процессора при активном обмене данными между клиентами будет также весьма приличной, поскольку при большом количестве потоков будет происходить очень много переключений контекста, а каждое переключение мы оцениваем в 50000 тактов. Существуют гораздо более удачные варианты решения задачи транзита данных: асинхронные сокеты и порты завершения ввода/вывода. И в том и в другом способе используется фиксированное количество потоков (например, 8 потоков для 4-ядерного процессора) и требуется намного меньше ОЗУ (как минимум, в 10 раз меньше, чем при использовании `TIdTCPServer`). Количество переключений контекста также намного меньше (сравнение имеет смысл производить только при высокой интенсивности обмена данными), т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40075821
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам.
лучше: так как в одном потоке могут быть обработаны сразу множество соединений и нет необходимости переключать контекст.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40075881
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
автор т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам.

лучше: так как в одном потоке могут быть обработаны сразу множество соединений и нет необходимости переключать контекст.

Хорошо, я поправлю. На самом деле я этот момент я не проверял. Рассчитываю на то, что если я ошибаюсь (ну может для асинхронных сокетов каждое событие генерирует переключение контекста), то знающие люди меня поправят :)
Но надеюсь, что работает так, как я думаю (в том числе для портов завершения ввода-вывода).
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40076097
Benten
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Автору большой респект за огромный труд и низкий поклон от меня!

Это не руководство для начинающих программистов, а скорее руководство для любых программистов, которые начинают писать многопоточные приложения на Delphi.
Такую тему надо закреплять в шапке форума. Например, очень удобно сделано на форуме 4PDA, там весь важный материал в шапке на первой же странице.

P.S. Зашел на ваш Github и с удивлением выяснил, что оказывается я давно уже использую ваш модуль LDSLogger.
Спасибо большое за вашу библиотеку, работает безотказно, несмотря сильное развитие возможностей языка Delphi в последних версиях Embarcadero Delphi.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40083038
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Benten, спасибо за столь высокую оценку моих трудов.

Добавлен новый раздел : Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой.

Ссылка на пример пример (проверял в D2007 и 10.4)

Вводная часть:

При разработке приложения очень часто, в ответ на действия пользователя, приходится запускать на выполнение код, длительность которого может составить несколько секунд, при этом должен устанавливаться запрет на дальнейшие действия пользователя с программой, до тех пор, пока длительный код не завершит свою работу. С такими ситуациями мы встречаемся очень часто, например:

при нажатии кнопки выполняем запрос к базе данных, а затем показываем пользователю результат запроса в новом окне;
выполняем операцию с банковской картой;
выполняем пробитие чека на кассе;
выполняем формирование отчёта;
отображаем на экране окно, которое в событии FormCreate выполняет длительную загрузку данных (из файла или из базы данных);
сохраняем изменения, внесённые в документ;
и т.д.
Во всех случаях пользователю необходимо дождаться, пока операция не будет завершена. Пока операция выполняется, использование программы является бессмысленным. Более того, если мы возьмём, и просто запустим выполнение длительной операции в дополнительном потоке, не блокируя интерфейс пользователя, то пользователь может нажать что-нибудь лишнее, в результате чего программа может перейти в непредсказуемое состояние. При таком способе запуска длительной операции, для блокировки интерфейса пользователя рекомендуется выставить свойство Enabled := False для всех элементов, с которыми пользователь может взаимодействовать с помощью мыши либо клавиатуры, а также запретить закрытие окна (с помощью параметра CanClose в обработчике FormCloseQuery).

Конечно, вы можете запустить длительный код в контексте основного потока. При этом пользователь не сможет ничего лишнего нажать до завершения операции (не забудьте изменить текст нажатой кнопки и курсор мыши на время выполнения операции - так пользователь будет хотябы понимать, что программа отреагировала на его действие и чем-то занимается). Если операция выполняется несколько секунд без какого-либо информирования пользователя, то пользоваться такой программой будет неприятно. Ещё хуже, если Windows повесит собственное окно с надписью "не отвечает" - в этом случае у пользователя может сложиться впечатление, что программа зависла. Если программа находится в таком состоянии более 30 секунд, то с большой вероятностью пользователь может попытаться решить "проблему" кардинально с помощью диспетчера задач либо путём перезагрузки компьютера.

Вы можете перед началом длительной операции отобразить на экране дополнительное окно к надписью "Выполняется операция ХХХ. Ждите!", а в конце операции закрыть его (см п. 1.2). Однако при таком способе есть несколько минусов:

Невозможно отобразить прошедшее время выполнения операции;
Windows может навесить собственное окно с надписью "Не отвечает", после чего возможна проблема с "вылетом" текущего окна на задний план (в этом случае пользователь не сможет ничего нажать в окне, которое находится на переднем плане и может принять кардинальное решение о перезагрузке компьютера);
В программе не работают никакие автоматические операции, запускающиеся из основного потока (обработчик TTimer.OnTimer не будет вызываться, пока основной поток не освободится);
Основной поток не обрабатывает вызовы SendMessage, PostMessage, Synchronize, Queue;
Если в программе используются асинхронные сетевые компоненты, использующие основной поток (например, Overbyte ICS), то их работа будет приостановлена, а соединения могут быть разорваны;
Сложно организовать информирование пользователя о текущем состоянии выполняемой операции;
Невозможно прервать ход выполнения длительной операции, даже если прерывание операции логично и не приводит к каким-либо проблемам (например, при формировании отчёта).
Далее демонстрируется пример, в котором все перечисленные проблемы решены! По сути, это готовое решение, котором можно использовать практически в любом VCL-проекте. Но мне хотелось бы, чтобы читатель досконально разобрался с исходными кодами. Мною было потрачено на этот пример много дней и весь код я постарался привести в максимально читабельный вид. Также мною разработан модуль ParamsUtils.pas, который значительно упрощает передачу именованного списка параметров различного типа, что весьма полезно в ситуации, когда мы не можем напрямую вызвать целевую функцию с её "родными" параметрами.

В папке ExWaitWindow находится пример, в котором демонстрируется способ отображения дополнительного модального окна при запуске длительной операции с помощью функции DoOperationInThread. Ниже пример использования функции DoOperationInThread:

procedure TMainForm.Button3Click(Sender: TObject);
begin
DoOperationInThread(Self, OPERATION_TYPE_NONE, 'Длительные вычисления',
TParamsRec.Build(['Min', 300, 'Max', 700]),
ProgressOperation, NEED_SHOW_STOP_BTN);
end;
В данном примере на экране отображается модальное окно с надписью "Длительные вычисления". Данное окно отображается на экране около 5 секунд. В этом окне отображаются следующие элементы:

Время, прошедшее от начала операции;
Полоса ProgressBar, которая индицирует ход вычислений;
Текущее значение, используемое в вычислительном алгоритме;
Границы вычисления Min и Max;
Кнопка "Отмена", позволяющая досрочно прервать выполнение операции.
⚠️ Внимание! Обратите внимание, что длительная операция запускается в дополнительном потоке!
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40083081
Softologic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DmSer

Добавлен новый раздел : Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой.

Респект! Полезная фича, действительно.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40083092
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DmSer

Добавлен новый раздел : Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой.

Хм, и VCL не штырит от такого?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40083096
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal,

Ни разу не жаловалась :-)
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40083305
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
У тебя же все равно в итоге форма в доп. треде. Надежней делать на чистом winapi
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40110999
jonik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer

Добавлен новый раздел: Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой.

Если честно не понял, для чего используется событие.
Давно не писал потоки, но по памяти. Создаем suspend поток и при отображении формы, в OnShow, стартуем его.
Как по мне есть вероятность на быстрой операции получить бесконечное ожидание, так как поток войдет в ожидание до отображения формы.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40111497
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jonik
DmSer

Добавлен новый раздел: Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой.

Если честно не понял, для чего используется событие.
Давно не писал потоки, но по памяти. Создаем suspend поток и при отображении формы, в OnShow, стартуем его.
Как по мне есть вероятность на быстрой операции получить бесконечное ожидание, так как поток войдет в ожидание до отображения формы.


Форма гарантированно отображается на экране. А закрывается только в одном месте - по команде из потока, после выполнения FEvent.WaitFor(INFINITE). Поэтому бесконечного ожидания не будет.

Существует бесконечное множество способов решить одну и ту же задачу. С эвентом - лишь один из способов.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40111620
jonik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня форма зависает. D10.3.3 и D10.4.2
Один или два раза отрабатывает норм, мелькает и закрывается. А в основном зависает. Если поставить задержку, то отрабатывает норм.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40111706
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jonik
У меня форма зависает. D10.3.3 и D10.4.2
Один или два раза отрабатывает норм, мелькает и закрывается. А в основном зависает. Если поставить задержку, то отрабатывает норм.


Что зависает? Мой пример?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40112005
jonik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, ваш пример, где быстрая операция. При чем зависает чаще, чем не зависает.
Один раз запускаю - мелькнуло, отработало. Запускаю сразу же ещё раз - зависает :)
Ну и так периодически. То есть как по мне код для быстрых операций не рабочий.
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40112007
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jonik
То есть как по мне код для быстрых операций не рабочий.

Что там за код, который "зависает"?
...
Рейтинг: 0 / 0
Многопоточное программирование в Delphi для начинающих
    #40112242
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jonik
Да, ваш пример, где быстрая операция. При чем зависает чаще, чем не зависает.
Один раз запускаю - мелькнуло, отработало. Запускаю сразу же ещё раз - зависает :)
Ну и так периодически. То есть как по мне код для быстрых операций не рабочий.


Пример с гитхаба не зависает.
Предполагаю, что вы скачали пример из гитхаба, что-то в нем подкрутили (может эвент удалили, я не знаю), после этого у вас стало зависать.

Попробуйте ещё раз скачать проект из гитхаба, в отдельную папку. Оттуда скомпилировать и запустить.
...
Рейтинг: 0 / 0
160 сообщений из 160, показаны все 7 страниц
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Многопоточное программирование в Delphi для начинающих
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]