Модераторы: 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   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

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

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

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

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


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

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


 




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


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

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