Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.01.2017, 10:00   #1
Ship_1
Форумчанин
 
Регистрация: 10.02.2014
Сообщений: 526
По умолчанию Недопонимаю про потоки. Как их можно "скрещивать"?

Здравствуйте.
Вот, например, я сделал программку для получения инфы про два принтера через веб-интерфейс. В одной процедуре я получаю очередь печати. Параметром в процедуру передаю IP принтера. Одна процедура у меня работает для двух принтеров.
Чтоб это всё не зависало, пока идёт получение информации, решил получение очереди перенести в поток.
Правильно ли я понимаю, что в потоках, в отличие от основного кода, информацию о двух принтерах я могу получать "параллельно"? Но тогда я уже не смогу обойтись одной процедурой - для каждого принтера придётся создавать свою, дублировать её в каждом потоке? Или как-то можно процедуру всё-таки оставить одну и вызывать её из двух потоков со своими параметрами?
Или я могу создать два экземпляра одного потока и запускать со своими параметрами, и это будет нормально?
И ещё недопонимаю про синхронизацию. Она нужна, если необходима строгая параллельность работы потока (потоков) и программы либо нескольких потоков? В моём случае она не нужна?
И ещё, в процедуре/функции можно сделать необязательный параметр со значением по умолчанию, например
Код:
... printer_nom:string = '90' ...
А как это сделать для потока?

Последний раз редактировалось Ship_1; 27.01.2017 в 10:13.
Ship_1 вне форума Ответить с цитированием
Старый 27.01.2017, 10:32   #2
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Цитата:
Сообщение от Ship_1 Посмотреть сообщение
Или как-то можно процедуру всё-таки оставить одну и вызывать её из двух потоков со своими параметрами?
Да. Только желательно чтобы она не взаимодействовала с чем-либо из других потоков (например, не писала что-то на форме), а просто выполняла запрос и возвращала результат. Ну или тогда придется синхронизировать это (TCriticalSection, ...).


Цитата:
Сообщение от Ship_1 Посмотреть сообщение
А как это сделать для потока?
так же? смотря что вы имеете в виду под потоком. Если экземпляр класса наследника TThread, то просто в конструктор это можно добавить, ну и поле в классе.

Код:
  TPrinterStatusLoaderThread = class(TThread)
  private
    FPrinterNumber: string;
  protected
    procedure Execute; override;
  public
    constructor Create(PrinterNumber: string = '90', CreateSuspended: Boolean = true);
  end;

...

constructor TPrinterStatusLoaderThread.Create(PrinterNumber: string = '90', CreateSuspended: Boolean = true);
begin
  inherited Create(CreateSuspended);

  FPrinterNumber := PrinterNumber;
end;

Результат работы потока тоже можно получать из public поля/свойства (заносить туда при получении инфы, читать в основном потоке после завершения), или событие/callback вызывать.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 27.01.2017 в 10:35.
Alex11223 вне форума Ответить с цитированием
Старый 27.01.2017, 10:36   #3
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Локальные переменные и параметры у каждого потока свои. Код дублировать не надо.

Цитата:
Или я могу создать два экземпляра одного потока и запускать со своими параметрами, и это будет нормально?
Именно так всё и работает.

Цитата:
И ещё недопонимаю про синхронизацию. Она нужна, если необходима строгая параллельность работы потока (потоков) и программы либо нескольких потоков? В моём случае она не нужна?
Если строгая, то не нужна. Но это недостижимый идеал. Веб-мора у вас общая для двух потоков. Поэтому от синхронизации вы никуда не денятись.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 27.01.2017, 10:39   #4
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Цитата:
Сообщение от Pavia Посмотреть сообщение
Веб-мора у вас общая для двух потоков. Поэтому от синхронизации вы никуда не денятись.
И? Это ж ее проблемы, а не клиента.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 27.01.2017, 11:01   #5
Ship_1
Форумчанин
 
Регистрация: 10.02.2014
Сообщений: 526
По умолчанию

Смотрю про потоки здесь. Как понял - синронизация забирает себе выполнение кода "засинхронизированной" процедуры до тех пор, пока она не выполнится? Или это только из-за "WaitFor", который необязателен?
В примере с синхронизацией уничтожение потоков происходит "вручную" и в теле execute потока. При этом переменные потока, судя по всему, глобальные. Мне глобальные не нужны. Можно ли их уничтожать в теле процедуры, из которой они записаны (типа bt1Click)?
У меня в потоке будет выполняться три процедуры:
1. Получение текста с веб-страницы (допустим, Proc1)
2. Обработка результата (Proc2)
3. Вывод результата на форму (Proc3).
Правильно ли я понимаю, что мне нужно
Код:
synchronize(Proc1);
Proc2;
synchronize(Proc3);
(процедура 2 ни с чем, кроме себя, не связана, поэтому её можно не синхронизировать)
Ship_1 вне форума Ответить с цитированием
Старый 27.01.2017, 11:03   #6
Ship_1
Форумчанин
 
Регистрация: 10.02.2014
Сообщений: 526
По умолчанию

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
И? Это ж ее проблемы, а не клиента.
А одновременное обращение к разным адресам через WinInt не вызывает ошибки?
Ship_1 вне форума Ответить с цитированием
Старый 27.01.2017, 11:06   #7
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Цитата:
Сообщение от Ship_1 Посмотреть сообщение
к разным адресам через WinInt не вызывает ошибки?
Смотря как, но вообще нет.
Цитата:
Сообщение от Ship_1 Посмотреть сообщение
Можно ли их уничтожать в теле процедуры, из которой они записаны (типа bt1Click)?
Зачем? Можно ж просто FreeOnTerminate:=true поставить.
Цитата:
Сообщение от Ship_1 Посмотреть сообщение
Вывод результата на форму (Proc3).
Лучше это делать в самой форме после завершения, как выше написано.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 27.01.2017 в 11:10.
Alex11223 вне форума Ответить с цитированием
Старый 27.01.2017, 11:13   #8
Ship_1
Форумчанин
 
Регистрация: 10.02.2014
Сообщений: 526
По умолчанию

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
Зачем? Можно ж просто FreeOnTerminate:=true поставить.
У меня создалось впечатление, что если у потока есть свойства, которым надо присвоить значение, то нужно сначала создать экземпляр потока, потом присвоить ему значения параметров, а потом уже запустить "вручную". И подумал, почему-то, что и уничтожать, соответственно, в этом случае нужно тоже вручную.
Ship_1 вне форума Ответить с цитированием
Старый 27.01.2017, 11:32   #9
Ship_1
Форумчанин
 
Регистрация: 10.02.2014
Сообщений: 526
По умолчанию

A execute у процесса обязательно должна быть процедурой или может быть функцией? Если только процедурой, то как грамотно "вывести" StringList из потока? Пока у меня этот процесс был в функциях и процедурах, я создавал StringList в функции, присваивая переменной значение этой функции, а уничтожал в основном коде после обработки. А как быть с потоком? Работать в нём со StringList можно, сделав StringList его полем. Но после завершения потока ведь и его поля уничтожаются. Или как раз для этого и существует уничтожение вручную: сначала обработать результаты, а потом уничтожить из основного кода?
И можно ли делать автоуничтожение, если пользоваться >вот такой< "конструкцией"? В этом случае сначала срабатывает процедура не потока, но вызванная в потоке, а автоуничтожение срабатывает только после её завершения, не смотря на то, что процедура не из потока?
Ship_1 вне форума Ответить с цитированием
Старый 27.01.2017, 12:01   #10
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Даже если бы он был функцией, это не помогло бы.
Я ж выше писал как.

Кстати, а почему Proc1 нужна синхронизация?


Вот более полный пример с callback (рядом код валялся, не помню почему использовал колбэк вместо события, и не помню как в Дельфи создавать события).

Код:
type
  TCallbackProc = procedure(PrinterNumber: string, Status: string, Error: Exception) of object;

  TPrinterStatusLoaderThread = class(TThread)
  private
    FPrinterNumber: string;
    FCallbackProc: TCallbackProc;
    FStatus: string;
    FError: Exception;
    procedure HandleTerminate;
  protected
    procedure Execute; override;
    procedure DoTerminate; override;
  public
    constructor Create(CallbackProc: TCallbackProc, PrinterNumber: string = '90', CreateSuspended: Boolean = true);
  end;

...

constructor TPrinterStatusLoaderThread.Create(CallbackProc: TCallbackProc, PrinterNumber: string = '90', CreateSuspended: Boolean = true);
begin
  inherited Create(CreateSuspended);

  FCallbackProc := CallbackProc;
  FPrinterNumber := PrinterNumber;
end;

procedure TZagryzkaThread.Execute;
begin
  try
    FStatus := GetPrinterStatus(FPrinterNumber);
  except on ex: Exception do
    begin
      FError := Exception.Create(ex.Message);
    end;
  end;
end;

procedure TPrinterStatusLoaderThread.DoTerminate;
begin
  Synchronize(HandleTerminate);
end;

procedure TPrinterStatusLoaderThread.HandleTerminate;
begin
  FCallbackProc(FPrinterNumber, FStatus, FError);
end;
Код:
TMyForm.....
......
private
    procedure PrinterThreadCallback(PrinterNumber: string, Status: string, Error: Exception);

.......


procedure TMyForm.PrinterThreadCallback(PrinterNumber: string, Status: string, Error: Exception);
begin
  if error = nil then
  begin
    ShowStatus(PrinterNumber, Status)
  end
  else
  begin
    ShowErrorMessage(error.Message);
  end;
end;


TMyForm.StartBtnClick.....
.....
  thread1 := TPrinterStatusLoaderThread.Create(PrinterThreadCallback);
  thread1.FreeOnTerminate := true;
  thread1.Resume;
  
  thread2 := TPrinterStatusLoaderThread.Create(PrinterThreadCallback, '42');
  thread2.FreeOnTerminate := true;
  thread2.Resume;
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 27.01.2017 в 12:06.
Alex11223 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как можно заменять "запятая" на "Enter" Silent-cry Microsoft Office Word 4 26.01.2018 12:03
Нужно пояснить/прокомментировать код программы, или коды функций "Добавить" "Удалить" "Обновить(редактировать" "Поиск" "Период") ZIRASS PHP 4 15.06.2016 14:23
Навеяно предыдущим топиком о Буфере обмена. Можно ли перехватить события "приКопированииВбуфер" и "приВставкеИзБуфера"? DBEER Microsoft Office Word 9 06.03.2016 23:45
Как обойти "преобразование типа из "string" в "float" невозможно" lexluter1988 Помощь студентам 1 07.08.2010 12:23