Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оформление кода потока, часто взаимодействует с формой 
:(
    Опции темы
Alix
Дата 1.10.2007, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



Нужно соединить две программы по сети. Использую WinSock2, впрочем это не важно. 
В каждой жмем "Соединиться" и начинается процесс соединения (кто сервер, кто клиент выбирается checkbox'ом). Процесс состоит из нескольких шагов, например для сервера они такие:
Код
  Создаем сервер
  Ожидаем подключение (ждем)
  Прием/передача данных, которые идентифицируют клиент, версию и некоторые другие параметры (посылаются в 2 этапа).

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

Получается что код метода Execute потока будет выглядеть примерно так:
Код

  statusText := 'Создаем сервер...';
  Synchronize(updateStatus);

  socket_server := server_start(server_port);
  if socket_server = INVALID_SOCKET then begin
    Synchronize(createServerFailed); 
  end;

  statusText := 'Ожидаем подключение...';
  Synchronize(updateStatus);

  socket_client := server_waitclient(socket_server);
  if socket_client = INVALID_SOCKET then begin
    Synchronize(waitClientFailed); 
    exit;
  end;

  ...

И мне придется создавать кучу методов аля чтотоТамFailed. А даже если и сделать один метод failed и устанавливать код выхода (failedCode := fcCreateServer), то это тоже кажется страшненьким решением.

Впрочем решения красивее я не вижу. Скажите, есть ли оно? Или, быть может, я неправильно использую потоки?


--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
stab
Дата 1.10.2007, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 14
Всего: 48



Я в таких случаях делаю события у потока, т.е. все методы вроде updateStatus или чтотоТамFailed находятся внутри класса-потока, а наружу они выдают обычные события в стиле VCL, например: DownloadFailed(Sender: TDownloader; Reason: TFailReason). Не думаю что лучшее решение есть.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Coder
Дата 1.10.2007, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 733
Регистрация: 13.12.2004

Репутация: 5
Всего: 11



Цитата(Alix @  1.10.2007,  23:40 Найти цитируемый пост)
Проблема в том, что этот процесс должен быть в любой момент отменен,

Может проверять на Terminate?
Код

      if Terminated then
         exit;


Цитата(Alix @  1.10.2007,  23:40 Найти цитируемый пост)
в случае же неудачи на любой из стадий он опять таки должен выполнять код, который должен быть синхронизирован. 

у тебя же есть statusText. Пишешь туда состояние и вызываешь одну процедуру синхронизации updateStatus

Цитата(Alix @  1.10.2007,  23:40 Найти цитируемый пост)
 А даже если и сделать один метод failed и устанавливать код выхода (failedCode := fcCreateServer), то это тоже кажется страшненьким решением.

почему страшненьким? сделай элементарный обработчик этих выходов:
Код

case failed of
  fcCreateServer : ;
  fcClientTimeout : ;
....
end;


Цитата(Alix @  1.10.2007,  23:40 Найти цитируемый пост)
socket_client := server_waitclient(socket_server);

Внутри server_waitclient() используется, как я понимаю, функция recv(), т.е. блокируящая сокет, то тебе перед ней советую вызывать select() и отлавливать таймауты.

PM MAIL   Вверх
Alix
Дата 1.10.2007, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



stab, можно чуть подробнее? Вызов типа 
Код
if Assigned(FOnStatusText) then
  FOnStatusText('message');
 ? А как же синхронизация?

Цитата
почему страшненьким? сделай элементарный обработчик этих выходов:

да, конечно, но я имел в виду что код функции execute будет как-то страшненько выглядеть

Цитата
Внутри server_waitclient() используется, как я понимаю, функция recv(), т.е. блокируящая сокет, то тебе перед ней советую вызывать select() и отлавливать таймауты.

нет, там используется accept:

Код
function server_waitclient(server : TSocket) : integer;
var
  client : TSockAddr;
  size   : integer;
begin
  size   := sizeof(client);
  result := accept(server, @client, @size);
end;



--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
stab
Дата 1.10.2007, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 14
Всего: 48



Цитата(Alix @  1.10.2007,  21:12 Найти цитируемый пост)
А как же синхронизация?

всё так же, через Synchronize(DoOnStatusMessage), а в DoOnStatusMessage уже собственно сам вызов обработчика события с параметрами.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Alix
Дата 1.10.2007, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



А в чем тогда коренное отличие от моего способа, кроме того, что вызывается какая-то функция на событие?


--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
stab
Дата 2.10.2007, 05:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 14
Всего: 48



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

2. Повышение уровня инкапсуляции, т.к. не требуется объявления в паблик секции свойст вроде StatusText или LastErrorCode, эти данные могут быть просто переданны в обработчик события. В общем, меньше публичных состояний системы - больше надёжности.

Если надёжность\реюсабельность\изменяемость кода не важна, эти два пункта - пустой звук. Всё зависит от контекста и объёма задача.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
ALeXandrK
Дата 2.10.2007, 06:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 342
Регистрация: 31.1.2007
Где: Санкт-Петербург

Репутация: 3
Всего: 6



Многопоточность - как это делается в Дельфи.
Там есть все, чтобы удачно применять потоки smile 
Пример на твою ситуацию там тоже есть...


--------------------
Богат не/ни тот, у кого много, а тот, кому хватает
PM WWW   Вверх
Felan
Дата 2.10.2007, 07:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



stab, прав. Только вот если так делать, то в события неудобно параметры передавать, т.к. в Synchronaze нельзя вызывать метод с параметрами.

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

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

Это сообщение отредактировал(а) Felan - 2.10.2007, 07:19


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Alix
Дата 2.10.2007, 08:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



Цитата
не требуется объявления в паблик секции свойст вроде StatusText или LastErrorCode

этого и так не делается...

Цитата
Только вот если так делать, то в события неудобно параметры передавать, т.к. в Synchronaze нельзя вызывать метод с параметрами.

Именно это я и имел в виду, когда говорил, что его код от моего мало отличается.

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

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

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


--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
stab
Дата 2.10.2007, 08:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 14
Всего: 48



Цитата(Alix @  2.10.2007,  12:09 Найти цитируемый пост)
этого и так не делается...


а это тогда зачем statusText := 'Создаем сервер...' ?

Цитата(Alix @  2.10.2007,  12:09 Найти цитируемый пост)
Именно это я и имел в виду, когда говорил, что его код от моего мало отличается.


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



--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Alix
Дата 2.10.2007, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



stab, ты написал:
Цитата
всё так же, через Synchronize(DoOnStatusMessage), а в DoOnStatusMessage уже собственно сам вызов обработчика события с параметрами.

Я понял это так:
Код

// в описании TMyThread:
  private
    statusText : string; // у меня сейчас так и есть

// в методе Execute
  ...
  statusText := 'Создаем сервер...';
  Synchronize(DoOnStatusMessage);
  ...

procedure TMyThread.DoOnStatusMessage;
begin
  if Assigned(FOnStatusMessage) then
    FOnStatusMessage(statusText);
end;

В моем же варианте все то же самое, только в DoOnStatusMessage находится не вызов обработчика, а непосредственно его тело.


--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
Felan
Дата 2.10.2007, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Цитата(Alix @  2.10.2007,  10:09 Найти цитируемый пост)
Никакого управления состоянием быть не должно. Код в потоке выполняется последовательно и там нет циклов. 

Ну так и не делай его. Все остальное ровно то же самое.

Я не пойму чем тебе не нравятся приведенные варианты? Вариант 
stabа,  хорош когда у тебя все на событиях. Мой  - когда нужен постоянно следить за состоянием а индикация уже вторична.


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Alix
Дата 2.10.2007, 09:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


L45
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 4.5.2005
Где: Pskov/Spb

Репутация: 7
Всего: 23



Felan, просто твой вариант мне не подходит, а метод stab'a такой же как и у меня по сути, я просто не вижу разницы между его вариантом и тем, что я привел в первом посте. (кроме, конечно, того, что у него все основано на событиях).


--------------------
Знание только тогда знание, когда оно приобретено усилиями своей мысли, а не памятью (с) Л. Толстой
High tech. Low live. (с) Gardner Dozois
PM MAIL ICQ Skype   Вверх
stab
Дата 2.10.2007, 10:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 14
Всего: 48



Цитата(Alix @  2.10.2007,  13:27 Найти цитируемый пост)
В моем же варианте все то же самое, только в DoOnStatusMessage находится не вызов обработчика, а непосредственно его тело. 


а, ну ок тогда всё. я подумал что тема про события не была понята smile


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Felan
Дата 2.10.2007, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Alix, По сути ее и нет. smile

Ну можешь еще сообщения посылать. Но это изврат какой-то...

Короче, как придумаешь свой уникальный способ - отпишись. Интересно, чего ты там кардинально нового выдумаешь.


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Melancholic
Дата 4.10.2007, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.5.2007

Репутация: нет
Всего: нет



Тоже думал на эту тему. Приведу общую постановку проблемы в моём понимании:
  • Наша программа занимается вводом-выводом посредствам сокетов.
  • Помимо ввода-вывода она занимается какой-то полезной работой. 
  • В системах, которых ввод-вывод отнимает достаточно много процессорного времени, для того чтобы не грузить основной поток вопросами IO (InputOutput) мы запускаем дополнительную нить.
Это с точки зрения потоков. Теперь посмотрим на проблему со стороны объектов:
  • Есть сущность "Главная форма". Она отвечает за обработку данных, поступивших от IO.
  • Есть объект-поток, который и занимается вводом-выводом.
Отсюда следует что как минимум неэстетично грузить поток ввода-вывода задачами обработки, что и происходит в предложенных вариантах (обработчик события выполняется в дополнительном потоке). Это главное что меня смущает в предложенных вариантах, хотя на абслютную правоту не претендую и в ряде задач такой подход может быть вполне оправдан. 
Какие есть альтернативы? Итак, снова начну с общего описания (это решение я нашел вообще в статье про последовательный порт smile):
  • Мы рассматриваем вопрос взаимодействия потоков.
  • Взаимодействие можно организовать посылкой сообщений.
  • Можно воспользоваться тем, что потоки выполняются в одном адресном пространстве и для посылки сообщения изменить заранее оговоренную область памяти.
Здесь можно вспомнить о сообщениях windows и использовать их в качестве этой самой "области памяти". т. е. Ваш дополнительный поток просто посылает окну сообщения (виндовыми средствами), а окно их обрабатывает как угодно. 
Теперь к частностям:
  • Скажете: "Пример в студию". Отвечу - его у меня нет smile Это всё так... Мысли вслух.
  • Как избавить код функции потока от постоянных проверок? Очевидное решение - исключения. Чуть что, - raise exception, а в конце метода execute обработка этих исключений с посылкой сообщения окну.

PM MAIL   Вверх
Felan
Дата 4.10.2007, 08:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Цитата(Melancholic @  4.10.2007,  09:48 Найти цитируемый пост)
Это с точки зрения потоков. Теперь посмотрим на проблему со стороны объектов:

    * Есть сущность "Главная форма". Она отвечает за обработку данных, поступивших от IO.
    * Есть объект-поток, который и занимается вводом-выводом.

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


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

Но это все ИМХО после прочтения твоего ТЗ smile


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Melancholic
Дата 4.10.2007, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.5.2007

Репутация: нет
Всего: нет



Вы правы, Felan, наши варианты похожи. За той лишь разницей что в моём случае поток ВВ сигнализирует о наступлении события посылкой сообщения, а в вашем состояние объекта-потока периодически проверяется таймером формы. Какой из вариантов применять - дело вкуса. Кстати если задача IO нересурсоёмка, то можно вообще использовать асинхронный ВВ, основанный на сообщениях (если кто не в курсе, то винда сама может уведомлять форму о наступлении события на сокете посылкой сообщения - и не надо никаких дополнительных потоков). (см. Использование сокетов в Delphi. Часть вторая: сокеты Windows, Антон Григорьев, дата публикации 01-10-2004 14:52 или описание функции WSAAsyncSelect в MSDN).
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0706 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.