Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 295
Delphi 6-7

Выполнение задачи в нескольких потоках, основные принципы, синхронизация

09.02.2022, 18:58. Показов 1801. Ответов 33

Студворк — интернет-сервис помощи студентам
Тему создал чтобы не флудить в соседней.
Собственно тестовый проект.
Пока интересует вопрос связанный конкретно с вызовом этого кода из потока :
Delphi
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
procedure LoadTXT_Thread.Execute;
var i,j,P,NeedFind,WhereFind,Tasks,STRt,FNSh:Integer;
 t1,t2,freq:Int64;
begin
  { Place thread code here }
   QueryPerformanceFrequency(freq);
    QueryPerformanceCounter(t1);
   NeedFind:=FfindL.Count-1;
   WhereFind:=FStringL.Count-1;
   Tasks:=WhereFind div Cores;
 
   for i:=0 to Cores-1 do
   begin
     STRt:=i*Tasks;
     FNSh:=(i+1)*Tasks;
     if i>0 then STRt:=strt+1;
     if (i=Cores-1) then FNSh:=WhereFind;
   SearchArr[i]:=Search_Thread.Create(Form1.ThreadTerm,FfindL,FStringL,STRt,FNSh,False);
    Log(form1.mmo1,IntToStr(i)+' THread '+IntToStr(STRt)+'--'+IntToStr(FNSh)) ;
   // Log(form1.mmo1,IntToStr(i)+' THread '+IntToStr(STRt)+'--'+IntToStr(FNSh)) ;
   end;
{ for i:=0 to FfindL.Count-1 do
    for j:=0 to FStringL.Count-1 do
     begin
      p:= pos(FfindL[i],FStringL[j]);
      if p>0 then begin
      FCompared.Add(FfindL[i]+' '+FStringL[j]+' ');
         PostMessage(Form1.Handle,MY_PROGRESS,0,Round(i*100/maxx));
       end;
 
     end;  }
      QueryPerformanceCounter(t2);
   Log(form1.mmo1,FormatFloat('0.000000',(t2-t1)/freq)+' Time to start 20 Threads') ;
    Log(form1.mmo1,'----------------------------') ;
    Log(form1.mmo1,IntToStr(Tasks)+' Tasks') ;
    Log(form1.mmo1,IntToStr(NeedFind)+' NeedFind') ;
    Log(form1.mmo1,IntToStr(WhereFind)+' WhereFind') ;
    Log(form1.mmo1,IntToStr(Length(SearchArr))+' Length_Array') ;
   // PostMessage(Form1.Handle,MY_PROGRESS,MY_END_PROGRESS,Handle);
 end;
А именно его вызов без синхронизации в контексте какого потока происходит?
Delphi
1
2
3
4
5
procedure LoadTXT_Thread.Log(var M: TMemo;SS:string);
begin
//
 m.Lines.Add(SS);
end;
Вложения
Тип файла: zip STRING_THR20.zip (283.0 Кб, 5 просмотров)
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.02.2022, 18:58
Ответы с готовыми решениями:

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

основные комбинатроные принципы
1. Если авиакомпания осуществляет 15 рейсов из Сан-Франциско в Чикаго и 20 рейсов из Чикаго в Нью-Йорк, то сколько всего рейсов из...

Основные принципы среды С
Все С-системы в общем состоит из 3 частей: среды программирования, собственного языка и стандартой библиотеки С. Вопрос: Что...

33
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
09.02.2022, 19:04
Цитата Сообщение от Иван Ежик Посмотреть сообщение
А именно его вызов без синхронизации в контексте какого потока происходит?
Насколько я вижу, в контексте этого же потока.
1
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 295
09.02.2022, 19:29  [ТС]
Constcat,
Вот, спасибо, я с самого начала хотел избавиться от этого способа логгирования.
Ну он по крайней мере только из одного потока выполняется,и только он пишет в это Memo.

Добавлено через 19 минут
Цитата Сообщение от Constcat Посмотреть сообщение
Насколько я вижу, в контексте этого же потока
Что сразу приходит в голову,это использовать внутреннее поле потока String
И через PostMessage отправлять адрес этой строки в основной поток.
Там процедура вынет строку и поместит в memo .
как вам такой вариант?
0
Модератор
4115 / 2347 / 807
Регистрация: 15.11.2015
Сообщений: 9,328
09.02.2022, 19:54
Цитата Сообщение от Иван Ежик Посмотреть сообщение
Там процедура вынет строку и поместит в memo .
А есть гарантия, что строка не будет изменена, пока сообщение не обработано?
0
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 295
09.02.2022, 20:16  [ТС]
Цитата Сообщение от AzAtom Посмотреть сообщение
А есть гарантия, что строка не будет изменена, пока сообщение не обработано
В голове у меня есть.
Ну это все лишь лог для визуальной оценки работы.
даже если ничего не придёт не критично.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
09.02.2022, 20:17
Цитата Сообщение от Иван Ежик Посмотреть сообщение
даже если ничего не придёт не критично.
Критично будет, если в основном потоке будет обращение к переменной в тот момент, когда туда производится запись фоновым потоком. Можно поймать Access Violation.
0
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 295
09.02.2022, 20:51  [ТС]
Цитата Сообщение от Constcat Посмотреть сообщение
Можно поймать Access Violation.
Согласен, лучше делать через синхронизацию.

Потом обдумаю как.
0
Модератор
4115 / 2347 / 807
Регистрация: 15.11.2015
Сообщений: 9,328
09.02.2022, 21:00
Можно использовать массив char неизменяемого размера, а извлекать, как PChar строку. Тогда, даже если поток начнёт писать следующее сообщение, то считывающий поток хоть и прочитает наложенные строки, но не вылетит с исключением и штатно остановится на нуле. Ну это вариант, если корректность строк не важна.

Другой вариант, для каждой строки в потоке выделять память и в сообщении отправлять адрес, а в считывающем потоке считывать и освобождать память. Но тут опять надо быть уверенным, что генерация не обгонит считывание.
1
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
09.02.2022, 21:35
Цитата Сообщение от AzAtom Посмотреть сообщение
Другой вариант, для каждой строки в потоке выделять память и в сообщении отправлять адрес, а в считывающем потоке считывать и освобождать память. Но тут опять надо быть уверенным, что генерация не обгонит считывание.
Угу. Игрался я с таким. Накидывал одним потоком очередь сообщений, другим - считывал.
Для очереди подходит, а вот для одной переменной я бы синхронизацию использовал. Тем более, что там потери в производительности практически никакие.
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 10:19
Цитата Сообщение от Иван Ежик Посмотреть сообщение
Потом обдумаю как.
Лучше сразу делать правильно и не вводить в метод Execute обращение к визуальным компонетам основного потока. Никаких и никогда.

Цитата Сообщение от Иван Ежик Посмотреть сообщение
я с самого начала хотел избавиться от этого способа логгирования.
правильно
0
 Аватар для krapotkin
6847 / 4674 / 1463
Регистрация: 14.04.2014
Сообщений: 20,656
Записей в блоге: 21
10.02.2022, 10:59
если лог не сильно флудит, то можно использовать вот такую конструкцию

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
TLogger = class
 ..
  LogFile : TWriterStream;
  LogStrings : TStrings;
  procedure Log(const s : String);
end;
 
procedure TLogger.Log(const s : String);
begin
  TThread.ForceQueue(
     procedure 
     begin
       if s <> '' then
         LogFile.Write( formatdatetime('hh:nn:ss.zzz ', now) + s );
       if Logstrings<>NIL then
         Logstrings.Add( formatdatetime('hh:nn:ss.zzz ', now) + s );
       LogFile.WriteLine;
     end;
  );
end;
объявить и инициализировать глобальную переменную проекта
Log : TLogger;
в каждый поток, чтобы не нарушать принцип инкапсуляции, передавать ссылку на него

и тогда в любом месте, потокобезопасно
Delphi
1
Log.Log('1234567890');
у меня такой класс используется в боевых программах
1
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 12:13
krapotkin, я тут понемногу изучаю интерфейсы (раньше обходил стороной), в связи с этим хочется всё заинтерфейсить (шютка ). В общем, сваял тут на основе твоей идеи логгер. Работает, а нюанс в том, что в моей ХЕ7 нет ForceQueue, поэтому использовал просто Queue. Это потокобезопасно? Я не вникал в отличия между этими методами.
поток, логгер
Delphi
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
unit Unit11;
 
interface
 
uses
  System.Classes, System.SysUtils;
 
type
  ILogger = interface
    function GetLog: TStrings;
    procedure Log(const S: string);
    property LogStrings: TStrings read GetLog;
  end;
 
  TMyThread = class(TThread)
  private
    FLogger: ILogger;
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;
 
var
  Logger: ILogger;
 
{============================================================}
implementation {=============================================}
{============================================================}
 
type
  TLogger = class(TInterfacedObject,ILogger)
  private
    FLogStrings: TStrings;
    function GetLog: TStrings;
  public
    procedure Log(const S: string);
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;
 
{ TMyThread }
 
constructor TMyThread.Create;
begin
  inherited Create(true);
  FreeOnTerminate:= true;
  FLogger:= Logger;
end;
 
procedure TMyThread.Execute;
var
  i: byte;
begin
  for i in [1..10] do
  begin
    FLogger.Log(ClassName + ' says: ' + i.ToString);
    Sleep(100);
  end;
end;
 
{ TLogger }
 
procedure TLogger.AfterConstruction;
begin
  inherited;
  FLogStrings:= TStringList.Create;
end;
 
procedure TLogger.BeforeDestruction;
begin
  FLogStrings.Free;
  inherited;
end;
 
function TLogger.GetLog: TStrings;
begin
  Result:= FLogStrings;
end;
 
procedure TLogger.Log(const S: string);
begin
  TThread.Queue(nil,
  procedure begin
    FLogStrings.Add(S);
  end);
end;
 
initialization
  Logger:= TLogger.Create;
end.

прога
Delphi
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
unit Unit10;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
  TForm10 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure OnThreadEnd(Sender: TObject);
  end;
 
var
  Form10: TForm10;
 
implementation
 
{$R *.dfm}
 
uses Unit11;
 
{ TForm10 }
 
procedure TForm10.Button1Click(Sender: TObject);
begin
  with TMyThread.Create do
  begin
    OnTerminate:= OnThreadEnd;
    Start;
  end;
end;
 
procedure TForm10.OnThreadEnd(Sender: TObject);
begin
  Memo1.Text:= Logger.LogStrings.Text;
end;
 
end.
Миниатюры
Выполнение задачи в нескольких потоках, основные принципы, синхронизация  
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
10.02.2022, 12:20
Цитата Сообщение от DenNik Посмотреть сообщение
procedure TMyThread.Execute;
var
  i: byte;
begin
  for i in [1..10] do
  begin
    FLogger.Log(ClassName + ' says: ' + i.ToString);
    Sleep(100);
  end;
end;
Не понял насчет переменной i. Она вроде как локальная и вроде как не меняется.
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 12:24
Цитата Сообщение от Пытливый Посмотреть сообщение
и вроде как не меняется
меняется
for i in [1..10] do

это просто нагрузка на поток. тут тестируется логгер, а не поток
0
Модератор
4115 / 2347 / 807
Регистрация: 15.11.2015
Сообщений: 9,328
10.02.2022, 12:24
Цитата Сообщение от Пытливый Посмотреть сообщение
и вроде как не меняется
Да вроде меняется от 1 до 10. Это же цикл.
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 12:25
меняется - см. картинку)
0
 Аватар для Пытливый
3763 / 2267 / 705
Регистрация: 29.05.2013
Сообщений: 9,622
10.02.2022, 12:28
Тфу ты плин, переклинило. Смотрю в книгу - вижу фигу. Я вместо цикла вижу:
Delphi
1
if i in [1..10]
и несколько охреневаю в попытке понять как же там i увеличивается
0
 Аватар для krapotkin
6847 / 4674 / 1463
Регистрация: 14.04.2014
Сообщений: 20,656
Записей в блоге: 21
10.02.2022, 12:55
разница между Queue и ForceQueue только в том, что когда Queue вызывается из главного потока, ни в какую очередь ничего не встает, и выполняется сразу.
ForceQueue пофиг, какой поток, все - в очередь.

p.s.
использовать тип byte в современных программах бессмысленно
все равно загружается весь регистр процессора. а там 64 бита, между прочим. и для работы именно с байтом, надо еще и сделать маску/сбросить остальные биты. так что лучше
1) не выпендриваться
2) for i := 1 to 10 do

))))

Добавлено через 5 минут
еще вопрос про интерфейсы
этот класс создается один раз в начале работы программы и удаляется в конце
зачем вся эта возня со сложными объявлениями
и зачем эти afterConstruction / beforeDestruction?
мне кажется классика тут гораздо чище выглядит:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TMyClass = class
public
  SomeObject : TMyObject;
  constructor Create;
  destructor Destroy; override;
end;
 
constructor TMyClass.Create;
begin
  SomeObject := TMyObject.Create;
end;
 
destructor TMyClass.Destroy; 
begin
  FreeAndNil(SomeObject);
  inherited Destroy;
end;
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 13:17
Цитата Сообщение от krapotkin Посмотреть сообщение
еще вопрос про интерфейсы
этот класс создается один раз в начале работы программы и удаляется в конце
зачем вся эта возня со сложными объявлениями
набиваю руку в плане интерфейсов

Цитата Сообщение от krapotkin Посмотреть сообщение
и зачем эти afterConstruction / beforeDestruction?
а разница? AfterConstruction выполняется сразу после конструктора, соответственно, BeforeDestruction - перед вызовом деструктора. Если выбор - или описать конструктор, или метод AfterConstruction - лично я разницы не вижу
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
10.02.2022, 14:17
Цитата Сообщение от krapotkin Посмотреть сообщение
использовать тип byte в современных программах бессмысленно
все равно загружается весь регистр процессора.
что это означает?

Цитата Сообщение от krapotkin Посмотреть сообщение
и для работы именно с байтом, надо еще и сделать маску/сбросить остальные биты
зачем?

в целом, по данному вопросу спорить не буду, ибо не компетентен. я провёл эксперимент:

- как это коррелирует с вышесказанным?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.02.2022, 14:17
Помогаю со студенческими работами здесь

Основные принципы Squid!
Подскажите пожалуйста краткий план работы Squid? Для начала хочу разобраться ограничить доступ к определенным сайтам для одного IP. Заранее...

Основные принципы WCF
Доброго времени суток господа. Вот на эту тему нужна в общем литература, и хотелось бы видеть перечисление этих принципов. здесь написано,...

Основные принципы создания грида
Подскажите пожалуйста основные принципы создания грида. Сетка, данные и пр.

Задание основные принципы ООП
Что требуется выполнить: -описать базовый класс Животное (Animal), у которого будут виртуальные методы &quot;говорить&quot;,...

Основные принципы создания плагинов
Какие существуют основные принципы создания плагинов


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru