Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2 3 4 5      [все]
 Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Работаю над учебником "Многопоточное программирование в 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


Сообщение было отредактировано: 8 июл 20, 16:52
8 июл 20, 12:09    [22163946]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1143
DmSer,

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

Сообщение было отредактировано: 8 июл 20, 13:27
8 июл 20, 13:24    [22164020]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
s62
DmSer,

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


Спасибо за предложение! Но мне кажется, это будет лишняя информация для начинающих. Очень сложно разобраться, какой материал нужно включать, какой не нужно. Тонкостей различных миллион! Если описывать про CreateThread, а это чисто виндовая функция, тогда придётся описывать аналоги и в других ОС (Linux, MacOS, Android). Вероятно, можно будет обойтись более общей формулировкой о том, что доп. поток на самом деле создаёт ОС, а класс TThread является обёрткой...
8 июл 20, 14:03    [22164064]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50816

DmSer
Если описывать про CreateThread, а это чисто виндовая функция

Причём такая, которой не надо пользоваться практически никогда. _beginthreadex() описать
таки надо. Хотя бы пробы было понимание, что "TThread это не поток".

Posted via ActualForum NNTP Server 1.5

8 июл 20, 14:17    [22164081]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1143
DmSer
Вероятно, можно будет обойтись более общей формулировкой о том, что доп. поток на самом деле создаёт ОС, а класс TThread является обёрткой...
Ну да, можно и как-то так.
8 июл 20, 15:41    [22164154]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
DmSer
Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

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

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

К сообщению приложен файл. Размер - 46Kb
8 июл 20, 16:24    [22164174]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Гаджимурадов Рустам
Member

Откуда:
Сообщений: 61561
DmSer> Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

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

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

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

Posted via ActualForum NNTP Server 1.5

8 июл 20, 16:56    [22164212]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
Чтобы разрабатывать реальные проекты надо не многопоточность изучать, а терминологию и практики...

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

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

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

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

Поэтому лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.
8 июл 20, 17:04    [22164227]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
автор
Я хотел бы выделить две основные причины использования многопоточности в Delphi-программах
Задачи длительного ожидания завершения ввода-вывода.

Вы путаете теплое с мягким. Такие задачи должны выполняться асинхронно.. Другой поток - это способ реализации, при чем довольно не эффективный, если таких запросов много.
8 июл 20, 17:24    [22164241]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
Первый пример показан через оверхед.
Намного лаконичнее решается через
TThread.CreateAnonymousThread(
    procedure
    var
      V: Int64;
    begin
      V := DoLongCalculations;
      MyShowMessage('Результат: ' + IntToStr(V));
    end
  ).Start();

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

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

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

Иначе книжку надо переименовать в Работа с классом TThread, а не многопоточное программирование...
8 июл 20, 18:15    [22164296]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
X-Cite
лучше, чтобы появлялись книжки, которые позволят вчерашним студентам, которые не знают как там работает под капотом, да и не надо им знать, но которые будут эффективно решать реальные бизнес-задачи используя современные инструменты.
Если человек не понимает (и/или не знает), как работает под капотом, то при первой же проблеме ему придётся либо разобраться в этом, либо сменить профессию.
8 июл 20, 18:23    [22164304]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
X-Cite
TTask.Run

Что будет, если DoLongCalculations будет выполняться часами, а пользователь захочет закрыть программу?
Нежданчик?
И таким "современным" методам вы предлагаете учить молодежь? Чтобы они и не знали, как сделать по-нормальному, чтобы контролировать всё?
8 июл 20, 18:29    [22164310]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
YuRock,

Почти все проблемы для известных и популярных библиотек уже описаны и описаны способы решения. В том числе например и для PPL. Проще обучить как решать задачи для которых PPL предпочтительнее, чем решать эти же задачи на TThread
8 июл 20, 18:30    [22164311]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
X-Cite
YuRock,

Почти все проблемы для известных и популярных библиотек уже описаны и описаны способы решения. В том числе например и для PPL. Проще обучить как решать задачи для которых PPL предпочтительнее, чем решать эти же задачи на TThread
Проблемы всегда появляются в логике решения любой задачи.
Какие нафиг библиотеки, я не про них говорю, а про реальные проекты, которые будут делать программисты.
Научить TTask'у, конечно, проще, чем TThread'у, только толку от этого ученика не будет.
8 июл 20, 18:34    [22164312]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 805
YuRock
X-Cite
TTask.Run

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

жданчик будет. Ошибки, зависания, прочие прелести.
Я от TTask отказался как раз из-за абсолютно фантастических вещей при его остановке.
8 июл 20, 18:39    [22164314]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
YuRock

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


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

Примеры:
  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
+
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
+
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) Произвести запись в файл используя отдельный поток.
8 июл 20, 19:54    [22164355]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
shalamyansky
Member

Откуда:
Сообщений: 161
X-Cite

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

С чего бы? GUI-поток завершится, но это не беда. Процесс будет жить, пока другой поток (другие потоки) не закончит свою работу. Вторичному потоку, который пишет в файл, от бывшего главного вроде бы ничего не нужно. Допишет файл, и тихо выйдет. По идее. На практике не проверил. Единственно, что вызывает сомнения - не будет ли сломан менеджер памяти, который должен на выходе из процедуры освободить байтовый массив. На первый взгляд, не будет.
8 июл 20, 20:42    [22164379]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Док

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


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


Док

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


Пишу в ворде 2010года. Про markdown не знал, спасибо. Почитаю, пока отпуск!
В идеале хотелось бы пользоваться специализированным решением, которое было бы совместимо с системой контроля версий. Но при этом не тратить много времени.
8 июл 20, 22:31    [22164431]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Гаджимурадов Рустам
DmSer> Работаю над учебником "Многопоточное программирование в Delphi для начинающих".

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


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

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

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

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


Я использую модуль TimeIntervals, там есть класс TTimeInterval, который является рекордом с методами. В D7 такое не скомпилится. Также я предполагаю, что в D7 были бы проблемы с отображением исходников в кодировке UTF-8. А мне приходится использовать UTF-8 для корректного отображения в гитхабе.
8 июл 20, 22:40    [22164437]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
X-Cite
Чтобы разрабатывать реальные проекты надо не многопоточность изучать, а терминологию и практики...

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

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

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

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

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


Я достаточно много думал о том, нужно ли описывать базовые вещи, или сразу начать с PPL. Моя уверенность в том, что важнее описать базовые вещи укрепилась после серии вопросов на этом форуме, которые относятся к PPL, а также к CreateAnonymousThread от начинающих программистов и не очень. Да, начинающего программиста можно, как мартышку, научить выполнять конкретное действие через TTask.Run. Но он нихрена не понимает, как это работает, если не знает базовые вещи. Проблема в Дельфи в том, что там нет того асинхронного программирования, которое есть в C#, JavaScript, Rust, Kotlin и некоторых других ЯП. В ЯП, где есть асинхронная конструкция async/await (либо аналоги), программисты решают реальные бизнес-задачи и как раз там им не требуется задумываться о том, как задача будет выполнена: параллельно, асинхронно или синхронно. В языках, которые изначально спроектированы как многопоточные (имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!
8 июл 20, 22:58    [22164442]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
X-Cite
автор
Я хотел бы выделить две основные причины использования многопоточности в Delphi-программах
Задачи длительного ожидания завершения ввода-вывода.

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


Да, должны! Но какого объёма книжку нужно написать для начинающего, чтобы он смог написать красивую, надёжную, быструю программу с использованием, скажем Overbyte ICS? А будет ли он читать такую книгу? А что ему даст асинхронность Overbyte ICS (какое преимущество), если ему потребовалось запрос к БД выполнить? А будет ли он читать такую книгу, если тут на форуме все примеры в основном на Indy?
8 июл 20, 23:04    [22164445]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
X-Cite

Потому что
TTask.Run(
    procedure
    var
      V: Int64;
    begin
      V := DoLongCalculations;
      MyShowMessage('Результат: ' + IntToStr(V));
    end
  );

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

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

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


В интернете достаточно хороших примеров того, как использовать PPL. Мне и добавить к ним нечего. Пусть начинающие учатся по этим примерам, ради Бога! Если удастся работать эффективно, я буду только рад за них.
8 июл 20, 23:09    [22164449]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9867
Хорошо работающая PPL это благо для начинающих (и не только).
Либо заголовок не правильный, либо план учебника ...
8 июл 20, 23:26    [22164461]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
X-Cite
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, нужно останавливать таски перед завершением программы, а в таске проверять необходимость завершения :)
8 июл 20, 23:27    [22164462]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9867
DmSer
Оказывается ...

Так ты знаешь PPL или только TThread ? :)
8 июл 20, 23:32    [22164468]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Dmitry Arefiev
Хорошо работающая PPL это благо для начинающих (и не только).
Либо заголовок не правильный, либо план учебника ...


Возможно в будущем появятся разделы, посвящённые PPL. Тем более PPL все активнее вторгается в нашу жизнь :) Но и помимо PPL есть много тем, которые хотелось бы описать (например, руки пока не дошли до описания темы синхронизации между потоками, а это, я считаю, очень важно). Но благодаря реализации функции ThreadWaitTimeout удаётся до последнего оттягивать такую сложную для понимания тему, как эвенты.
8 июл 20, 23:34    [22164470]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Dmitry Arefiev
DmSer
Оказывается ...

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


Я изучал довольно много материала по PPL, смотрел видео-уроки, проводил некоторые эксперименты, так что считаю, что знаю о ней достаточно много.
8 июл 20, 23:37    [22164471]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
DmSer
X-Cite
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, нужно останавливать таски перед завершением программы, а в таске проверять необходимость завершения :)


Это еще не идёт речь о том, что часто потоки нужно завершать в определенном порядке. Как это сделать с тасками - объяснить начинающему программисту будет проблематично :)
9 июл 20, 00:32    [22164484]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Дегтярев Евгений
Member

Откуда: Барнаул
Сообщений: 1903
DmSer
(имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!

ты про шедулершедулер или gc?
9 июл 20, 06:17    [22164501]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Дегтярев Евгений
DmSer
(имею ввиду прежде всего GoLang) в сто раз меньше связанных с многопоточностью проблем и граблей, чем в языке Delphi. А теперь им еще и шедулер улучшили!

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


Раньше кооперативный планировщик был, а работу планировщика ОС они грубо говоря игнорировали. Теперь учитывают.
9 июл 20, 08:50    [22164521]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
YuRock

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


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

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

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

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

Если говорить о теме топика, то я не понимаю что такое многопоточное программирование. Есть решение задач с помощью потоков - это уже звучит по другому. И как минимум понятно, что не все задачи можно и нужно решать с помощью потоков.

Сообщение было отредактировано: 9 июл 20, 10:37
9 июл 20, 10:38    [22164548]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Дегтярев Евгений
Member

Откуда: Барнаул
Сообщений: 1903
DmSer
Дегтярев Евгений
пропущено...
ты про шедулершедулер или gc?

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

видимо у авторов были веские причины запилить это, но как по мне оно решает настолько нетипичную для гошного кода ситуацию
9 июл 20, 20:03    [22164833]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26714
У меня ощущение, что многие критикующие пропустили важные слова - "для начинающих".
10 июл 20, 00:16    [22164956]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 6014
X-Cite
Если говорить о теме топика, то я не понимаю что такое многопоточное программирование. Есть решение задач с помощью потоков - это уже звучит по другому. И как минимум понятно, что не все задачи можно и нужно решать с помощью потоков.
Это умение "сшивать" взаимодействие потоков и знать как использовать различные способы синхронизации. А что-то там считать - ничем от однопоточного не отличается
10 июл 20, 08:32    [22164997]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 6014
X-Cite
Проблема в Дельфи в том, что разработчики которые туда пытаются придти учатся по книжкам которые написаны были во времена высокого порога входа в программирование, а не когда курсы клепают по 100 "программистов" в день...

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

1. проблема в том, что такие "программисты" никому и не нужны - если они не чисто за корочкой идут
2. нету реальных бизнес-задач с потоками, которые могут решать "прошедшие курсы" :-)
10 июл 20, 08:38    [22165001]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
wadman
У меня ощущение, что многие критикующие пропустили важные слова - "для начинающих".

просто пиписьками меряются друг перед другом. Другого объяснения нет
10 июл 20, 09:03    [22165012]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
DmSer,
я не уверен, но может быть при ручном убиении потока кошернее делать экземпляру потока не просто Free, а Free + Nil?

Я обычно провожу проверку на существование предыдущего экземпляра прежде, чем запустить новый, типа:
type
Form1 = class(TForm)
...
private
FMyThread: TMyThread;
...
end;

procedure Button1Click...
begin
  //если сделать просто FMyThread.Free, то праздника не получится
  if Assigned(FMyThread) the Exit;
  ...
end;
10 июл 20, 09:16    [22165019]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Док
DmSer,
я не уверен, но может быть при ручном убиении потока кошернее делать экземпляру потока не просто Free, а Free + Nil?

Я обычно провожу проверку на существование предыдущего экземпляра прежде, чем запустить новый, типа:
type
Form1 = class(TForm)
...
private
FMyThread: TMyThread;
...
end;

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


Конечно, так и нужно. А в каком примере nil отсутствует? Вроде следил, чтобы везде было!
10 июл 20, 14:40    [22165302]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
DmSer
А в каком примере nil отсутствует?

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

стр 16
10 июл 20, 14:48    [22165307]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Док
DmSer
А в каком примере nil отсутствует?

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

стр 16


Здесь нормально, тут же FormDestroy! Есть примеры, где объект потока уничтожается при нажатии на кнопку, вот там ссылка обнуляется и есть объяснение зачем это делается.
10 июл 20, 15:31    [22165349]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Bred eFeM
Member

Откуда:
Сообщений: 550
DmSer,
Респект за работу!

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

+
(руки пока не дошли до описания темы синхронизации между потоками, а это, я считаю, очень важно).
Мдя... (может рассказать о нескольких способах кормления философов на примерах?)
11 июл 20, 19:49    [22165803]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Bred eFeM
Мдя... (может рассказать о нескольких способах кормления философов на примерах?)


Я не уверен в пользе такого подхода. Помню, на 2-м или 3-м курсе университета были занятия, на которых преподавали многопоточность по философам (библиотека Gala), анимация интересная, но вряд ли кто-то из студентов смог извлечь из неё что-то полезное. А преподаватель вообще был не знаком с этой библиотекой :)

Сообщение было отредактировано: 12 июл 20, 00:22
12 июл 20, 00:21    [22165886]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Учебник сохранён в формате markdown. Очень удобная вещь оказалась. Текст в итоге читается вроде не хуже, чем в docx. ссылка
28 июл 20, 20:05    [22174839]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
white_nigger
Member

Откуда: Тула
Сообщений: 2354
Не понравилось буквально в первом примере это:
procedure TMyThread.Execute;
var
  V: Int64;
begin
  FreeOnTerminate := True;
  V := DoLongCalculations;
  MyShowMessage('Результат: ' + IntToStr(V));
end;

Как только начинающий захочет заменить MyShowMessage на показ своей супер-пупер формы - он может нехило обломаться. Обязательно надо подчеркнуть что все UI вещи (по крайней мере VCL) надо выполнить в Synchronize или Queue. Понятно что в примере голый WinApi и там и так прокатит, но лучше сразу показать. Вместо апишного вызова лучше взять делфёвый ShowMessage
28 июл 20, 22:37    [22174890]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
white_nigger
Не понравилось буквально в первом примере это:
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 из доп. потока.
28 июл 20, 23:53    [22174909]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
Пробежал по диагонали. Классная статья получилась. Для полноты картины еще бы неплохо добавить разделы про эвенты, мьютексы, семафоры. Я, например, про эвенты кое-как наскреб инфу в инете, потому методом проб и ошибок дотумкал, как они работают :)
29 июл 20, 14:28    [22175166]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Док
Пробежал по диагонали. Классная статья получилась. Для полноты картины еще бы неплохо добавить разделы про эвенты, мьютексы, семафоры. Я, например, про эвенты кое-как наскреб инфу в инете, потому методом проб и ошибок дотумкал, как они работают :)


Спасибо!

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

Раньше я очень часто использовал эвенты, мьютексы, может даже злоупотреблял ими в какой-то степени. Сейчас гораздо реже. Выяснилось, что очень многие вещи можно сделать на крит. секции и циклах ожидания со Sleep :). Может так получается небольшой оверхед, но программа становится проще.
29 июл 20, 15:42    [22175249]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
и, как минимум, реализовать override-метод Execute.

и, как минимум, переопределить виртуальный метод Execute.


DmSer
⚠️ Запущенный поток не завершается при выходе из программы
Завершается
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. Новичкам об этих функциях вообще лучше не знать
29 июл 20, 16:17    [22175262]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
procedure TForm1.FormDestroy(Sender: TObject);
begin
  // При закрытии программы необходимо завершить работу потока
  // и уничтожить объект потока MyThread
  if MyThread <> nil then
    MyThread.Free;
end;
Ну и в чем великий смысл выделенной строчки? Если
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;
29 июл 20, 16:22    [22175264]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
Если же мы решим объявить для такого потока переменную и будем пытаться с нею работать, то рискуем нарваться на ошибку доступа к памяти «Access Violation», поскольку объект потока может быть уничтожен в любой момент времени.
Верно только для случая, когда поток завершается сам
29 июл 20, 16:49    [22175286]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
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_
Верно только для случая, когда поток завершается сам


Именно так!

Сообщение было отредактировано: 29 июл 20, 17:23
29 июл 20, 17:26    [22175311]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
InterlockedIncrement/InterlockedDecrement я бы заменил на кроссплатформенные AtomicIncrement/AtomicDecrement

DmSer
  // Создаём поток в спящем состоянии
  FMyThread := TMyThread.Create(True);

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

  // Пробуждаем поток для выполнения вычислений
  FMyThread.Resume;
Я бы инициализацию MaxValue вынес в конструктор. Чтобы не возникало желания его модифицировать

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

DmSer
procedure 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 резервирует для себя. И можно нарваться
29 июл 20, 17:28    [22175314]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
он также знает что такое override-метод.
Я впервые слышу такой термин. Я воспринимаю термин "override-метод" как "переопределенный" (в родителе) метод. У нас же в родителе метод абстрактный
DmSer
Спящий поток кушает примерно 1,3 МБ адресного пространства
Где?
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;

WorkingSet: 1: 20480, 2: 16384, 3: 32768, Total: 69632
PageFileSet: 1: 81920, 2: 86016, 3: 81920, Total: 249856
Rio 10.3.1. Сборка проекта Debug.
29 июл 20, 17:48    [22175329]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
В некоторых задачах (например, при математических вычислениях) следует по возможности избегать использования конструкций try..finally и try..except, т.к. они могут нести значительные накладные расходы.
Шта?

DmSer
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.


Ну и нет главы о передаче данных в дополнительный поток
29 июл 20, 18:17    [22175346]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
_Vasilisk_
DmSer
В некоторых задачах (например, при математических вычислениях) следует по возможности избегать использования конструкций try..finally и try..except, т.к. они могут нести значительные накладные расходы.
Шта?
+
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;
Clear: 9844, Finally: 11734, Except: 9922
2 секунды на миллиарде операций стоят того, чтобы отказываться от обработки ошибок?
29 июл 20, 18:33    [22175353]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
_Vasilisk_

DmSer
Спящий поток кушает примерно 1,3 МБ адресного пространства
Где?
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;

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


Причём тут pagefile? Речь же шла про виртуальное адресное пространство!

Сообщение было отредактировано: 29 июл 20, 19:34
29 июл 20, 19:36    [22175394]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
_Vasilisk_
_Vasilisk_
пропущено...
Шта?
+
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;
Clear: 9844, Finally: 11734, Except: 9922
2 секунды на миллиарде операций стоят того, чтобы отказываться от обработки ошибок?


Операция операции рознь. Чем тяжелее операция тем меньше разница. Отказываться от обработки ошибок не нужно. Но и совать её куда ни попадая не следует.
29 июл 20, 19:43    [22175397]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
_Vasilisk_
DmSer
procedure 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?
29 июл 20, 21:38    [22175427]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
_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.



Действительно я накосячил. Исправил. Доработал программу для исследования квантов и приоритетов.
29 июл 20, 22:13    [22175449]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
istrebitel
Member

Откуда:
Сообщений: 60
DmSer

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

http://delphimaster.net/view/1-59239
30 июл 20, 07:26    [22175501]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Еще поправил раздел о приоритетах спорная часть теперь выглядит так:

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

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

Относительный приоритет потока влияет на выделение процессорного времени как между потоками в рамках одного процесса, так и между потоками различных процессов.
30 июл 20, 08:40    [22175510]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
istrebitel
DmSer

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

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


Думаю, что WM_USER+100 нужен при разработке наследников от некоторых компонентов. А лучше изучать исходники и смотреть, какие коды там используются.
30 июл 20, 08:47    [22175512]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
DmSer
Одну и ту же вычислительную задачу быстрее (примерно в 3 раза) сможет решить приложение, которое находится на переднем плане.


Исправлено:

В том случае, если два приложения будут привязаны к одному ядру процессора, то одну и ту же вычислительную задачу быстрее (примерно в 3 раза) сможет решить приложение, которое находится на переднем плане.


Сообщение было отредактировано: 30 июл 20, 09:11
30 июл 20, 09:14    [22175522]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4509
DmSer,

От настроек зависит. На серверных виндах приоритет у фоновых задач.
Картинка с другого сайта.
30 июл 20, 09:46    [22175533]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Kazantsev Alexey
DmSer,

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


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

Сообщение было отредактировано: 30 июл 20, 12:34
30 июл 20, 12:37    [22175630]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4509
DmSer,

Да, про увеличение размера кванта написано у Русиновича, кажется (Внутреннее устройство Windows).
30 июл 20, 12:45    [22175632]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4509
Кстати, величина самого длинного кванта на Windows 2000 всего 36.
30 июл 20, 13:01    [22175646]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11971
DmSer
Счётчик ссылок может изменяться из разных потоков. Это безопасно в том случае, если строка не меняется.
Счетчик ссылок может стать нулем

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

Только программа имеет тенденцию развиваться и мне проще изначально писать правильно, чем потом выискивать места, где нужно что-то поправить
30 июл 20, 15:01    [22175731]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
_Vasilisk_
DmSer
Счётчик ссылок может изменяться из разных потоков. Это безопасно в том случае, если строка не меняется.
Счетчик ссылок может стать нулем


Речь идёт о "константной" строке, значение которой присваивается один раз и больше не меняется.
Счётчик станет нулём в том случае, если строка никому больше не нужна. В этом случае строка будет уничтожена, память освободится. Никаких проблем с многопоточным доступом тут нет. Конечно, можно на всякий случай каждую строчку кода защищать критической секцией и для каждой строки на всякий случай вызывать UniqueString. Но зачем?
30 июл 20, 16:10    [22175781]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1747
DmSer
_Vasilisk_
пропущено...
Счетчик ссылок может стать нулем


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


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

На моей памяти уже несколько лет не было случая, чтобы что-то блокировать, кроме очередей.
30 июл 20, 19:35    [22175868]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Добавлена информация о threadvar и немного о UniGui.
1 авг 20, 00:02    [22176441]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.
3 авг 20, 17:06    [22177111]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26714
Док
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.

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

Сказал посреднику, что хочешь сообщить главному и дальше пошел работать.
3 авг 20, 21:07    [22177192]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 6014
Док
Кстати, если интересно, вот тут https://forum.lazarus.freepascal.org/index.php/topic,40163.msg277111.html#msg277111 многие из авторов рекомендуют пользоваться Synchronize/Queue взамен привычных для винды SendMessage/PostMessage. Правда, это для Лазаря и с учетом кроссплатформенности.
и для VCL я это советую - 22162612
и на это есть много причин
4 авг 20, 09:25    [22177275]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
kealon(Ruslan)
и для VCL я это советую

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

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

Сообщение было отредактировано: 4 авг 20, 14:46
4 авг 20, 14:44    [22177462]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
wadman
Так я избавляюсь от ожидания.

сложно это все. Я проще поступаю: если надо дождаться в доп.потоке реакции от главного - делаю Synchronize/SendMessage, если пофиг - Queue/PostMessage :)

Сообщение было отредактировано: 4 авг 20, 14:44
4 авг 20, 14:46    [22177465]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50816

Док
если надо дождаться в доп.потоке реакции от главного - делаю Synchronize/SendMessage

В моё время Synchronize не принимал параметры и не позволял вернуть значение, приходилось
всё делать через левые переменные.

Posted via ActualForum NNTP Server 1.5

4 авг 20, 15:01    [22177479]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 805
Док
kealon(Ruslan)
и для VCL я это советую

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

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


а на деле вопрос получения трудновыловимых багов от Application.ProcessMessages в случае многопоточного приложения - это вопрос времени.
А первый раз, не зная куда копать - можно очень долго искать причину.
4 авг 20, 16:00    [22177514]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
Vizit0r
а на деле вопрос получения трудновыловимых багов от Application.ProcessMessages в случае многопоточного приложения - это вопрос времени.

да расслабьтесь, я его втыкаю только в тестовых приложениях :)
4 авг 20, 17:05    [22177554]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 805
Док,
я из своего опыта просто делюсь...
4 авг 20, 17:46    [22177575]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Vizit0r
Док
пропущено...

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

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


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


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

Например, были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока. Получается фигня. Лучше модальное окно показать с какой-нибудь анимацией и закрывать его при окончании работы потока. Причем модальное окно можно делать невидимым первые 5 секунд. Позже я опишу этот приём в "учебнике".
4 авг 20, 23:23    [22177677]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
rgreat
Member

Откуда:
Сообщений: 6058
DmSer
были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока
Нафига, если есть Timer и Event-ы?

ProcessMessages нужен для того что бы интерфейс не залипал при длительной работе в основном потоке. Да и то надо в уме держать возможные побочные эффекты, и например, отключать ненужные возможности по вводу данных в GUI.
4 авг 20, 23:48    [22177679]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
rgreat
DmSer
были попытки с помощью Application.ProcessMessages организовать цикл ожидания окончания работы дополнительного потока
Нафига, если есть Timer и Event-ы?

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


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


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

Сообщение было отредактировано: 5 авг 20, 08:34
5 авг 20, 08:37    [22177739]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
DmSer
rgreat
пропущено...
Нафига, если есть Timer и Event-ы?

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


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



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

О, господи.
Мне кажется, правильнее было бы реализовать "ожидание" убрав формирование отчета из доп потока в главный. Раз уж зачем-то нужно "ожидание".
5 авг 20, 09:33    [22177759]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
YuRock

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


В нашем случае ПО управляет ещё кучей устройств, главный поток дёргается постоянно, поэтому мы не можем надолго его блокировать.
5 авг 20, 09:53    [22177778]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
DmSer
запускался доп. поток для формирования отчета и выполнялось ожидание окончания формирования отчёта с помощью цикла:

а в доп.потоке-то оно зачем?
5 авг 20, 18:00    [22178135]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
roschinspb
Member

Откуда: С-Пб
Сообщений: 1636
Hi
Во-первых, хочу по-приветствовать идею написания книги, выразить моральную поддержку и пожелать творческих успехов.

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

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

Возможно стоит вынести код не в отдельный поток а в отдельное небольшое консольное приложение.
5 авг 20, 18:27    [22178160]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
roschinspb,
Спасибо за предложения! Я их проанализирую и постараюсь отразить в статье.
5 авг 20, 19:30    [22178183]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
roschinspb,

Сереж, у тебя же на "народе" небольшая статья была с примерами потоков...
5 авг 20, 23:09    [22178245]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 3701
roschinspb,

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


я бы не сказал, что так уж сложно и на порядок. достаточно придерживаться известных принципов: не лезть к vcl и к расшаренным ресурсам и в 99% случаев всё сразу же заработает. невизуальные компоненты, имеющие проблемы в многопоточке - скорее исключение.
долгие вычисления как правило предполагают много данных и гонять данные между приложениями в обе стороны - то еще удовольствие

Сообщение было отредактировано: 6 авг 20, 09:16
6 авг 20, 09:14    [22178314]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Zelius
Member

Откуда: Россия, Москва
Сообщений: 1429
makhaon,

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

доп процесс полезен если используются сторонние библиотеки, которые могут привести к зависанию программы. пришлось так делать когда использовал bass что бы писать интернет радио...
6 авг 20, 09:35    [22178323]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 805
Zelius
makhaon,

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

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


это скорее исключение.
А в целом - гораздо полезнее разобраться с потоками, чем с межпроцессным взаимодействием.
6 авг 20, 10:30    [22178358]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Zelius
Member

Откуда: Россия, Москва
Сообщений: 1429
Vizit0r,

полезнее знать что делать, когда программа виснет в чужой dll и никакие потоки не спасают, т.к. их не перезапустить...
6 авг 20, 11:22    [22178414]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Zelius
makhaon,

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

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


К сожалению, межпроцессное взаимодействие это не та задача, которая возникает у большинства Delphi-программистов каждый день. В RTL, если не ошибаюсь, нет практически ничего готового в помощь для решения этой задачи (я не говорю о взаимодействии по TCP или через COM, тут как раз более менее всё необходимое имеется). Если возникает задача организовать взаимодействие между процессами в рамках одного компьютера, то, думаю, каждый Delphi-программист вынужден мастерить свой велосипед.
6 авг 20, 12:08    [22178453]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
roschinspb,

а где предложение про Окно, отображающее ход выполне­ния длительной операции? :)
Было бы уместным!
С ним кстати не было проблем/сбоев? Работает во всех версиях Delphi?
6 авг 20, 12:16    [22178457]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Так или иначе, "учебник" в первую очередь о том, как научиться многопоточному программированию в Delphi (в идеале, для решения различных задач, где уместна многопоточность), а не о том, как решать различные задачи, не прибегая к многопоточному программированию.
6 авг 20, 12:20    [22178461]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 805
Zelius
Vizit0r,

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


это уже сильно частные случаи, на самом деле.
6 авг 20, 13:37    [22178549]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
roschinspb
Member

Откуда: С-Пб
Сообщений: 1636
DmSer
roschinspb,

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

Для начинающих пример сложноват. Это скорее для второго тома. Многопоточное программирование для тех, кто бросает. 😁. Вообще на сайте не последняя версия. Последняя с исправлениями для 64 бит погибла вместе с винчестером. Когдато яя её кому-то выслал, может где и есть еще.
6 авг 20, 15:32    [22178666]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
roschinspb
Member

Откуда: С-Пб
Сообщений: 1636
makhaon
невизуальные компоненты, имеющие проблемы в многопоточке - скорее исключение

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

makhaon

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

P.S. Я не призываю отказаться от тредов вообще и не надо меня убеждать в том что иногда они нужны. Я просто пытаюсь избавить от лишних проблем начинающих программеров и тех кто потом за ними будет код чистить.
6 авг 20, 17:43    [22178747]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Fr0sT-Brutal
Member

Откуда:
Сообщений: 344
Так вот кто гуглу насоветовал про процессы, так что теперь хром плодит свои копии интенсивней, чем зерглинги вылупляются!
7 авг 20, 00:40    [22178863]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Док
Member

Откуда: Казань
Сообщений: 6745
Fr0sT-Brutal
теперь хром плодит свои копии интенсивней, чем зерглинги вылупляются!

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

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

если только в таймере. Интересно, сколько таймеров можно запустить без заметного вреда для софтины?

Сообщение было отредактировано: 7 авг 20, 08:30
7 авг 20, 08:32    [22178915]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
cptngrb
Member

Откуда:
Сообщений: 588
мне кажется эта статья описывает многопоточность достаточно хорошо, многое оттуда взять можно [url=]https://forum.vingrad.ru/topic-60076.html[/url]
7 авг 20, 08:45    [22178921]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
cptngrb
мне кажется эта статья описывает многопоточность достаточно хорошо, многое оттуда взять можно [url=]https://forum.vingrad.ru/topic-60076.html[/url]


Да, я с нею знакомился. Она не для начинающих. Писалась в те времена, когда программирование было уделом гениев. Очень тяжело усваивается. Думаю, мало кто осилит дочитать более 30% (до БАБ врядли дело дойдет :)
7 авг 20, 10:36    [22178972]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1143
Zelius
...
пришлось так делать когда использовал bass что бы писать интернет радио...
Если не секрет, какой протокол от сервера к клиенту? Какой-нибудь HLS или Icecast?
7 авг 20, 18:50    [22179383]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
roschinspb
Member

Откуда: С-Пб
Сообщений: 1636
Док
. Интересно, сколько таймеров можно запустить без заметного вреда для софтины?
много. В fix чуть менее чем у всех контролов есть анимация, а она содержит таймер.
вчера, 04:16    [22179720]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1164
Добавлен раздел планирование потоков
вчера, 10:56    [22179749]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
ART-CODE
Member

Откуда:
Сообщений: 1091
Может пригодиться и такая инфа:

CAS
https://ru.wikipedia.org/wiki/Сравнение_с_обменом

FAA
https://en.wikipedia.org/wiki/Fetch-and-add
вчера, 18:01    [22179855]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
ART-CODE
Member

Откуда:
Сообщений: 1091
spinlock
https://ru.wikipedia.org/wiki/Спин-блокировка

I/O Completion Ports
https://docs.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports
------
Не всем, и не всегда нужна кроссплатформенность.
Бывает, что важнее выжать по-максимуму из возможностей ОС и процессора.
вчера, 18:15    [22179858]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Zelius
Member

Откуда: Россия, Москва
Сообщений: 1429
s62,

Использовал чтото высокоуровневое, просто урл передавал, под капот потока не смотрел
вчера, 21:11    [22179891]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: 1 2 3 4 5      [все]
Все форумы / Delphi Ответить