Передать данные в поток TThread

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Передать данные в поток TThread

Сообщение ssnakess » 19.07.2023 21:24:42

Сквозняк писал(а):
ssnakess писал(а):Из этого я понял. что Вы предлагаете не только в пишущем потоке ставить IsBusy в false, но и уведомлять еще когото.
кого?


Ну да. Если не надеетесь на потокобезопасность своего кода, то всегда можно завести внешнего бюрократа, которому будете оставлять заявки и получать или не получать разрешение на действие. Это займёт лишнее время, потому обращаться к нему нужно только когда велика вероятность его положительного ответа. Ну вот как-то так:
Код: Выделить всё
   
if not fLog.IsBusy Then if bjurokrat1(nomer_potoka) Then
      Begin
       fLog.IsBusy:=true;
       fLog.Messages.Append(msg);
       uvedomlenie_bjurokratu1(nomer_potoka);
       fLog.IsBusy:=false;




вот так понятно что Вы имели ввиду :)
вопрос откуда я возьму nomer_potoka?
т.е. я должен же его гдето взять в потоке ожидающем "свободного" буффера.
наверное это или случайное число (что хреново), или я где-то должен его "попросить", т.е. у такогож "бюрократа2"
а если есть "бюрократ2", у которого два потока одновременно попросят "номерок в очереди", то 100% могут получить одинаковый.
т.е. Ваша идея понятна, но грабли теже - несколько потоков пишут и/или просят данные у одного супер-потока

и еще есть нюанс, ИМХО, вот так:
Код: Выделить всё
if not fLog.IsBusy Then if bjurokrat1(nomer_potoka) Then
      Begin
       fLog.IsBusy:=true;
       fLog.Messages.Append(msg);
       uvedomlenie_bjurokratu1(nomer_potoka); // вот тут может быть засада не маленькая
       fLog.IsBusy:=false;

нельзя делать, ибо при вызове из двух разных потоков этого кода на выполнение, не известно какой мусор будет в стеке для переменной вот тут
Код: Выделить всё
procedure  uvedomlenie_bjurokratu1(nomer_potoka: longint); // переменная nomer_potoka хранится в стеке при вызове процедуры
begin
zajavki2[nomer_potoka]:=0;
zajavki1[nomer_potoka]:=0;
end;


дабы избежать приколов реализации компилятора - код потока должен быть для каждого свой, Вы можете использовать переменные потока и передавать потоку ссылку на внешнюю переменную, и уже внутри кода потока ею "злодействовать".
т.е. на этом же примере
Код: Выделить всё
if not fLog.IsBusy Then if bjurokrat1(nomer_potoka) Then
      Begin
       fLog.IsBusy:=true;
       fLog.Messages.Append(msg);
      zajavki2[nomer_potoka]:=0;
       zajavki1[nomer_potoka]:=0;
       fLog.IsBusy:=false;

[/code]
Вы поняли о чем я? :)
да, это фигово ибо дублируется код, но тут лучше сделать так, чем получить непонятки из-за непойми чего храянщегося в стеке при вызове процедуры из разных потоков.
ssnakess
новенький
 
Сообщения: 36
Зарегистрирован: 24.09.2011 23:08:55

Re: Передать данные в поток TThread

Сообщение Сквозняк » 19.07.2023 23:08:22

ssnakess писал(а):вопрос откуда я возьму nomer_potoka?


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

ssnakess писал(а):нельзя делать, ибо при вызове из двух разных потоков этого кода на выполнение, не известно какой мусор будет в стеке для переменной вот тут

Идея в том, что каждый поток пишет в свою собственную ячейку внешнего массива переменных типа byte. Это же вроде бы безопасно пока его длину не изменяют.
Сквозняк
энтузиаст
 
Сообщения: 1110
Зарегистрирован: 29.06.2006 22:08:32

Re: Передать данные в поток TThread

Сообщение ssnakess » 20.07.2023 09:09:21

Сквозняк писал(а):Всем потокам нужно предварительно выдать вручную или сделать, чтобы при создании они выбирали свободный номер, и в массивах zajavki1 и zajavki2 для этого номера были свободные ячейки.


Если количество потоков которые инициируют запись в лог - заранее не известно, то выдавать им в ручную - не вариант. А если они должны при создании получить свободный номер, то как?
обращаясь к супер-потоку - можем получить два одновременных обращения. Лезть каждому потоку по массиву и искать там свободный номер - тоже, можем выбрать два одинаковых.
Или можно "играть в рулетку", т.е. при создании потока, который хочет писать в лог, при известном заранее количестве ячеек массива zajavki, брать случайное число в этом диапазоне и использовать как индекс. Тогда чем больше будет количество ячеек массива, тем меньше вероятность коллизий, но тоже....

Похоже без критических секций, тут не обойтись.
тогда оформить поиск по массиву zayavki в критическую секцию. это достаточно быстрая процедура, т.е. поиск 0 в одноразмерном массиве, и вызвать сильные заморозки всей работы не должны.
Но критические секции, ИМХО, зло еще то :)

Или таки есть другой вариант, я так организовывал очередь сообщений между разными приложениями. Там приложения при работе получали внешние данные, обрабатывали их и клали файлики в папку.
Другое приложение, читало постоянно папку и при появлении там файла, читало его и выполняло работу, если ОК - стирало файл.
Похоже тут при взаимодействии потоков, это тоже самый железобетонный вариант :) поток который хочет записать в лог - пишет сощбщение в файл и самоубивается.
Поток пишущий лог - читает папку и собирает файлы в один, удаляя их из папки :)
ssnakess
новенький
 
Сообщения: 36
Зарегистрирован: 24.09.2011 23:08:55

Re: Передать данные в поток TThread

Сообщение Сквозняк » 20.07.2023 12:16:10

ssnakess писал(а):А если они должны при создании получить свободный номер, то как?


Процедуру вызвать конечно. Компьютеру всё равно что считать, можно и потоки, которые обратились. Например, назначать всем создаваемым потокам число -1 и при запихивании такого числа в процедуру, оно заменится на другое, положительное свободное. И не надо ничего рандомом назначать. Это обычное жонглирование кучей флагов-переменных и состояний многопозиционных переключателей. Надо такое несколько раз сделать, тогда понятно будет.

ssnakess писал(а):Похоже без критических секций, тут не обойтись.


Просто нет пока привычки прописывать кучу флагов ручками. Там конечно часто ошибаешься, но после отладки логики, она работает нормально. Хотя, если потоки плодятся безконтрольно, то выдачу им индивидуального номера всё-таки придётся сделать через критическую секцию, но это намного быстрее чем писать в файл.
Сквозняк
энтузиаст
 
Сообщения: 1110
Зарегистрирован: 29.06.2006 22:08:32

Re: Передать данные в поток TThread

Сообщение jsa » 21.07.2023 06:06:54

ssnakess писал(а):и у вас все будет работать, без таймера, очереди и прочего ;)

Есть 2 "но".

1. Так я вынес процесс записи в файл в отдельный поток. А он куда больше времени занимает чем выталкивание строки в очередь.
Если писать в файл прямо в процедуре IdHTTPServer1CommandGet то это существенно замедлит обработку запросов.
2. В лог пишет не только IdHTTPServer1CommandGet , там есть и другие процедры. И я так понимаю затык/наложение может приключиться в момент доступа к файлу на диске.
jsa
постоялец
 
Сообщения: 261
Зарегистрирован: 28.11.2017 13:46:04

Re: Передать данные в поток TThread

Сообщение iskander » 21.07.2023 11:39:57

ssnakess писал(а):Ну да. Если не надеетесь на потокобезопасность своего кода, то всегда можно завести внешнего бюрократа, которому будете оставлять заявки и получать или не получать разрешение на действие. Это займёт лишнее время, потому обращаться к нему нужно только когда велика вероятность его положительного ответа.

На правах Капитана: для правильной работы программы при конкурентном доступе к данным требуется гарантия, что во время записи к данным имеет доступ только пишущий поток.
То есть соответствующий участок кода должен быть огорожен какими-либо примитивами синхронизации.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Пред.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 110

Рейтинг@Mail.ru