Форум: "Основная";
Текущий архив: 2006.11.26;
Скачать: [xml.tar.bz2];
ВнизДополнительный поток и Exception в главном. Что будет? Найти похожие ветки
← →
Германн © (2006-10-16 01:31) [80]
> Kolan © (16.10.06 01:06) [70]
>
>
> > Возможно даже, что у тебя никогда проблемм и не будет,
> а
> > будут они у пользователей!
> >
>
> А какие. Пусть у меня перед сном вообще моск прокиснет и
> я как Гоголь возьму и сотру эти модули, которые писал и
> доробатывал 1,5 года :)
>
Ну вот давеча наблюдали всем техотделом такую ситуацию. В программе, где идёт работа с портом возникло исключение. Программа сдохла, но перезапустить её не было никакой возможности. Даже на CAD система не реагировала! :-)
← →
Kolan © (2006-10-16 01:34) [81]
> Не совсем. Т.е., Resume должен делать первичный поток.
Даааа... а в справке тока:Pauses a running thread
.
У меня поток сам себя усыпляет:
while not Terminated do
begin
if ReadIndex >= WriteIndex then
begin
Suspend;
//****
> Если это еще и Ex - то и, например, по получению QueueUserAPC.QueueUserAPC
Да, это я еще...
Я понял что вместо Suspend надо сделать
WaitForSingleObject(Event, INFINITE);
- не так? Нужен именно Ex? - С этой ф-цие не работал... :(
← →
Kolan © (2006-10-16 01:37) [82]
> В программе, где идёт работа с портом возникло исключение.
До сегодняшнего дня у меня небыло исключений. в окрестности порта. Ошибочки обрабатывал с пом. Enumeration.. Вот решил за исключения взяться.
А работа с портом в потоке - это из нета. А как еще чтобы не висло?
← →
Leonid Troyanovsky © (2006-10-16 01:41) [83]
> Kolan © (16.10.06 01:34) [81]
> У меня поток сам себя усыпляет:
Усыпиться-то он может. А вот resume нужен извне.
> WaitForSingleObject(Event, INFINITE); - не так? Нужен
> именно Ex? - С этой ф-цие не работал... :(
Ну, у молодых все еще спереди :)
Вкл., возможно, ReadFileEx & etc.
--
Regards, LVT.
← →
Kolan © (2006-10-16 01:41) [84]Да вот сюда я и попадаю со своим исключением.
{$IFDEF LINUX}
if Thread.FSuspended then sem_wait(Thread.FCreateSuspendedSem);
{$ENDIF}
try
if not Thread.Terminated then
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
end;
Отсюда и неверный дискриптор...
← →
Kolan © (2006-10-16 01:53) [85]
> А вот resume нужен извне.
Да это извне ессно.
При добавлении новых данных делается Resume. Все же тут разницы нет наверно. Что Resume что SetEvent...
> Ex
Надо посмотреть
> Да вот сюда я и попадаю со своим исключением.
Ни че не пойму с этими исключениями...
Если:try
SeparateHeaderAndUserDtaArrays(Package, Header, UserData);
except
Result.Free;
//raise;
end;
Это же исключение обработано? Так?
Так че оно вexcept
Thread.FFatalException := AcquireExceptionObject;
поподает?
← →
Германн © (2006-10-16 01:59) [86]
> Kolan © (16.10.06 01:37) [82]
>
>
> > В программе, где идёт работа с портом возникло исключение.
>
>
> До сегодняшнего дня у меня небыло исключений. в окрестности
> порта. Ошибочки обрабатывал с пом. Enumeration.. Вот решил
> за исключения взяться.
>
> А работа с портом в потоке - это из нета. А как еще чтобы
> не висло?
>
Дык, исторически микросхема UART представляла максимум возможностей для асинхронной работы с ней. Драйверы СОМ-порта в Windows умеют использовать эти возможности.
Ну а в Дельфи оьрати внимание на параметр FILE_FLAG_OVERLAPPED и на
← →
Kolan © (2006-10-16 08:30) [87]
> Ну а в Дельфи оьрати внимание на параметр FILE_FLAG_OVERLAPPED
> и на
Этим и пользуюсь. Те у меня асинхронная работа и в потоке :)
← →
Сергей М. © (2006-10-16 08:48) [88]
> Kolan © (16.10.06 08:30) [87]
> у меня асинхронная работа и в потоке
И зачем там нужна асинхронность ?
У тебя что, доп.поток еще чем-то занимается, кроме как работой с портом ?
← →
Rem © (2006-10-16 09:25) [89]У меня поток сам себя усыпляет:
while not Terminated do
begin
if ReadIndex >= WriteIndex then
begin
Suspend;
Очень трудно разобраться с приведенными фрагментами кода, и я не знаю, что такое ReadIndex и WriteIndex, однако, думаю, удобнее реализовать таким образом:
while not Terminated do
begin
while not Terminated and (ReadIndex >= WriteIndex) do
Sleep(0); // 10, 20 или другая цифра по условию задачи
{...}
end;
То есть, усыплять поток не надо будет...
← →
Kolan © (2006-10-16 10:16) [90]
> У тебя что, доп.поток еще чем-то занимается, кроме как работой
> с портом ?
Нет
> Очень трудно разобраться с приведенными фрагментами кода,
> и я не знаю, что такое ReadIndex и WriteIndex, однако,
> думаю, удобнее реализовать таким образом:
У меня там циклический буффер. Соотв индек по которому пишу данные и индекс по которому читаю и ищу начало/конец пакета.
> Sleep(0);
Гы :) Было и такое решение. Ну а зачем? А если данные часами не прийдут? Че он будет молотить в пустую?
← →
Percent (2006-10-16 10:27) [91]Че он будет молотить в пустую?
Предлагаешь выключить компьютер? :-)
Поставь Sleep(50), и не мучайся...
← →
Сергей М. © (2006-10-16 10:30) [92]
> Kolan © (16.10.06 10:16) [90]
> Нет
Тогда зачем асинхронный режим задействован ?
← →
Kolan © (2006-10-16 10:42) [93]
> Тогда зачем асинхронный режим задействован ?
ХЗ. Дела я все это по статье:
http://morgeyz.elayne.ru/comlpt.htm
В конце статьи:Теперь, но ОЧЕНЬ кратко, залезем в еще большие дебри. Предположим, что протокол обмена с Вашим устройством, подключенным к последовательному порту, очень сложен (передаются большие и сложные структуры данных). При этом Ваша программа должна получать уже полностью принятую и проверенную информацию. Предположим так же, что Ваша программа занимается очень большими и сложными вычислениями и ей нет времени отвлекаться на обработку ввода/вывода. Да и сложность ее такова, что встраивание фонового ввода/вывода сделает ее трудно прослеживаемой и неустойчивой. Чувствуете, куда я клоню? Правильно, к выделению всех тонкостей ввода/вывода в отдельный поток. Возможно выделение и в отдельную задачу, но в этом случае мы не получим никакой выгоды, а накладные расходы на переключение задач гораздо больше, нежели на переключение потоков в одной задаче.
Прям про мою задачу :) Вот я и выделил...
← →
Kolan © (2006-10-16 10:42) [94]
>
> Предлагаешь выключить компьютер? :-)
>
> Поставь Sleep(50), и не мучайся...
>
Все же усыплять - красивше :) У меня тогда душа спокойна :)...
← →
Kolan © (2006-10-16 10:49) [95]
> Ни че не пойму с этими исключениями...
Как бы так и продолжаю не понимать :)
Думаю сделаю так:
В еще одном потоке "обработки" завиду очередь пакетов. При получении пакета буду туда добавлять и будить его. Поток будет просыпаться выбирать пкеты и обрабатывать. Ну как?
Дальше обработав пакет(массив) он будет создавать объект пакет.
И отдавать на обработку гл потоку. Опять же как тут быть? Опять Synchronize(DoSmth)? Получится тоже самое... Только теперь другой поток будет ждать пока DoSmth не завершится..
← →
Сергей М. © (2006-10-16 10:54) [96]
> Kolan © (16.10.06 10:42) [93]
Цитата из той же статьи:
Так как в потоке ввода/вывода, выполняющемся параллельно основному потоку программы, можно использовать асинхронный ввод/вывод, то достаточно просто реализуется возможность обработки большого количества портов
Твой доп.поток работает всего лишь с одним портом, а не с несколькими одновременно.
Чем в этом случае оправдан выбор асинхронного режима ?
← →
Kolan © (2006-10-16 10:56) [97]
> Чем в этом случае оправдан выбор асинхронного режима ?
Смешно конечно звучит: Чтобы форма не висла... Работает пока и бог с ним. Тут бы это передеалть.. А с портом видно будет. Порт кстати пока не подводил...
← →
Сергей М. © (2006-10-16 11:06) [98]
> Kolan © (16.10.06 10:56) [97]
> Смешно конечно звучит: Чтобы форма не висла
Ты даже не представляешь, насколько это смешно)..
Чтобы форма "не висла", ты как раз и задействовал доп.поток.
А уж как работает этот твой доп.поток с тем или иным устройством - синхронно или асинхронно - форме (еще точнее - основному потоку) отныне абсолютно фиолетово.
Так что сам собой напрашивается вывод - асинхр.режим выбран тобой от балды и сложность его прогр.реализации (ощутимо повышенная по отношению к синхр.режима) ничем пока не оправдана.
← →
Kolan © (2006-10-16 11:13) [99]
> асинхр.режим выбран тобой от балды и сложность его прогр.
> реализации (ощутимо повышенная по отношению к синхр.режима)
> ничем пока не оправдана.
Ну не оправдан, знаю что до конца не разобрался. Сделал по статье - акуратно. Работатет не подводит. Уже сделано, зачем менять?
← →
Сергей М. © (2006-10-16 11:42) [100]
> Kolan © (16.10.06 11:13) [99]
> Сделал по статье - акуратно
suspend твой в доп.потоке - тоже по статье ?)
← →
Kolan © (2006-10-16 11:54) [101]
> suspend твой в доп.потоке - тоже по статье ?)
Причем тут это??? Я понимаю ветку ниасилили :)
Мы тут говорим НЕ о ПТОКЕ ЧНЕНИЯ ИЗ ПОРТА(который ессно не спит), а о другом потоке, Который ищет в полученых из порта данных пакет.
← →
Сергей М. © (2006-10-16 12:12) [102]
> Kolan © (16.10.06 11:54) [101]
> ветку ниасилили
Эт точно)
В ней много шуму из ничего.
Если не вдаваться в подробности изначально неразумно спроектированной тобой логики разделения функциональности приложения (между потоками ее процесса), то ответ на вопрос был уже дан, и он прост как 2х2:
try
synchronize(...)
except
... //никаких re-raise, если отсутствует перехват и обработка исключений уровнем выше !
end;
← →
Kolan © (2006-10-16 12:17) [103]Может мне для передечи сообщения, чтобы все осталось внутри модуля и не трогало гл. форму, создать формочку прямо в
TConnectionManager
ТеTConnectionManager = class
FForm: TForm;
А получив пакет я его скопирую и пошлю сообщениеprocedure TConnectionManager.PackageReceivedEvent(Sender: TObject;
Package: array of Byte);
begin
//Копирую
PostMessage();
end;
Нормальный маривант?
← →
Kolan © (2006-10-16 12:30) [104]и сообщени передать Self те указательна экземпляр
TConnectionManager
, а форма вызовет:TConnectionManger(Pointer).ProsessPackage
// Ну или как там правильно преобразовать указатель в объект.
В итоге дальше модуля сTConnectionManger
дело не пойдет. И Synchronize закончится быстро. :)
Но ответа я дождусь, а то опять перепахивать все :)
← →
Ketmar © (2006-10-16 17:46) [105]бр-р-р. что-то мне подсказывает, что ты спроектировал софт "от балды", совершенно не представляя, зачем там потоки, и что они должны делать. и как, собственно, вся эта механика работает. сорри, но у всех вопросов лапы растут явно оттуда. есть предложение: выспаться, плотно подумать и переписать всё заново. %-)
← →
Kolan © (2006-10-16 18:12) [106]
> бр-р-р. что-то мне подсказывает, что ты спроектировал софт
> "от балды", совершенно не представляя, зачем там потоки,
> и что они должны делать. и как, собственно, вся эта механика
> работает.
Все же некоторое представление о том что там да как имею. :)
> Kolan © (16.10.06 12:17) [103]
Дык это брр?
Итак я получил пакет. Как мне сделать дальше. Как спроектировать?procedure TConnectionManager.PackageReceivedEvent(Sender: TObject;
Package: array of Byte);
begin
if Assigned(FConnectionManagerPackageReceivedEvent) then
FConnectionManagerPackageReceivedEvent(Self, Package);
end;
Система примерно такая
1. Есть главный менеджер в который композитно входит менеджер измерений(Он знает логику измерения).
2. В менеджере измерений есть менеджер устройства, который знает о протоколе.
3. Менеджер устройства использует менеджер связи(TConnectionManager), который обрабатывает данные и отправляет в порт.
Так вот форма в лучшем случае знает о Главном менеджере. Как быть? Сообщение посылать неудобно.
Как перепроектировать?
← →
Kolan © (2006-10-16 18:22) [107]Те я ка бы последовательно пользуюсь паттерном фасад.
← →
Kolan © (2006-10-16 19:13) [108]Короче, потом не говорите, что плохо :)
TConnectionManager
- точно должен быть фасадом. У него всего две функции предать пакет и выдать принятый, а там хот через сеть может передаваться. Делаю короче через окно(окно-поле этого менеджера) и сплю спокойно...
← →
Percent (2006-10-16 19:39) [109]1. Есть главный менеджер в который композитно входит менеджер измерений(Он знает логику измерения).
2. В менеджере измерений есть менеджер устройства, который знает о протоколе.
3. Менеджер устройства использует менеджер связи(TConnectionManager), который обрабатывает данные и отправляет в порт.
И в чем проблема? Каждый менеджер пусть обрабатывает свой участок работы.
1. Менеджер связи - отсылает пакеты и ждет приходящих пакетов. Сделай у него события OnConnect, OnDisconnect, OnPacketReceived, OnError. И метод отправки пакета.
2. Менеджер устройства - пусть собирает пакеты для отправки и разбирает пакеты при пролучении.
3. Менеджер измерений пусть анализирует принятую информацию. И подготавливает данные измерений.
Ты бы хоть бы название софта озвучил бы. И логику его работы описал. То есть, для чего это все?
← →
Leonid Troyanovsky © (2006-10-16 19:42) [110]
> Kolan © (16.10.06 18:12) [106]
> Как перепроектировать?
До главного менеджера боюсь, что не осилю, но,
для обработки ошибок в потоке могу предложить такой паттерн:
type
EThreadException = class(Exception);
TMyThread = class(TThread)
procedure Execute; override;
private
..
Error: Exception;
procedure ShowError;
procedure ShowResult;
end;
procedure TMyThread.ShowExcept;
begin
Application.ShowException(Error);
end;
procedure TMyThread.Execute;
begin
while not Terminated do
try
..
raise EThreadException.Create("..."); // если что-то не так
..
Synchronize(ShowResult); // показываем результат
..
except
on E: EThreadException do // мы знаем, как исправить ситуацию
begin
Error := E;
Synchronize(ShowExcept); // если нужен показ
{корректирующие действия}
end;
on E: Exception do // мы не знаем, как реагировать на другие ошибки
begin
Error:= E;
Synchronize(ShowExcept); // показываем исключение
Terminate; // завершаем поток
end;
end;
end;
Что произойдет, если исключение возникнет в ShowResult?
Если внутри метода нет обработчиков, исключение попадет в except потока. Если это известное исключение (EThreadException), то его можно
обработать и, возможно, поток продолжит работу.
Для неизвестных исключений продолжать поток смысла нет.
Схема может быть использована непосредственно
для тех потоков, которые отзываются на Termianate.
А, например, поток, ожидающий в ReadFile ввода не в состоянии
реагировать на установку Terminated, т.е., нуждается в
дополнительных управляющих сигналах.
Ну, и не должны потоки быть suspended.
Это для потока не рабочее состояние, а скорее отладочное.
--
Regards, LVT.
← →
Kolan © (2006-10-16 20:01) [111]
> И в чем проблема? Каждый менеджер пусть обрабатывает свой
> участок работы.
Именно так они и работают...
> Leonid Troyanovsky © (16.10.06 19:42) [110]
>
>
Благодарю. Идея понятная. Буду пользоваться.
Но в денном случае, опираясь на ваш код. ВSynchronize(ShowResult);
мне надо лишь отправить пакет дальше... и Тут же вернуться. Те никаких исключений в потоке не будет.
Вот я и спрашиваю можно ли замутить с формой?
> Ну, и не должны потоки быть suspended.
> Это для потока не рабочее состояние, а скорее отладочное.
>
Буду медетировать на это.
← →
Percent (2006-10-16 20:06) [112]Вот я и спрашиваю можно ли замутить с формой?
Перефразируй, пожалуйста...
← →
Kolan © (2006-10-16 20:10) [113]Вот короче этот злашастный менеджер целиком:
TConnectionManager = class
private
FCommPort: TAnisochronousComm;
FCommReadThread: TAnisochronousCommReadThread;
FPackageComposer: TPackageComposer;
FPackageExtractor: TPackageExtractor;
FConnectionManagerPackageReceivedEvent:
TConnectionManagerPackageReceivedEvent;
protected
{Events}
procedure CommReadEvent(Sender: TObject;
ReadBytes: array of Byte);
procedure SendPackageReadyEvent(Sender: TObject;
Package: array of Byte);
procedure PackageReceivedEvent(Sender: TObject;
Package: array of Byte);
public
constructor Create;
destructor Destroy; override;
procedure SendPackage(Package: array of Byte);
property ConnectionManagerPackageReceivedEvent:
TConnectionManagerPackageReceivedEvent read
FConnectionManagerPackageReceivedEvent write
FConnectionManagerPackageReceivedEvent;
end;procedure TConnectionManager.CommReadEvent(Sender: TObject;
ReadBytes: array of Byte);
begin
FPackageExtractor.AddArray(ReadBytes);
end;
constructor TConnectionManager.Create;
begin
inherited Create;
FCommPort := TAnisochronousComm.Create;
FCommPort.Open;
FCommReadThread := TAnisochronousCommReadThread.Create(FCommPort);
FCommReadThread.CommReadEvent := CommReadEvent;
FPackageComposer := TPackageComposer.Create(StartByte, EndByte, LastByte);
FPackageComposer.SendPackageReadyEvent := SendPackageReadyEvent;
FPackageExtractor := TPackageExtractor.Create(StartByte, EndByte);
FPackageExtractor.PackageReceivedEvent := PackageReceivedEvent;
end;
destructor TConnectionManager.Destroy;
begin
FCommPort.Free;
FCommReadThread.Terminate;
FCommReadThread.Resume;
FPackageComposer.Free;
FPackageExtractor.Terminate;
FPackageExtractor.Resume;
Sleep(10);
inherited Destroy;
end;procedure TConnectionManager.PackageReceivedEvent(Sender: TObject;
Package: array of Byte);
begin
if Assigned(FConnectionManagerPackageReceivedEvent) then
FConnectionManagerPackageReceivedEvent(Self, Package);
end;
procedure TConnectionManager.SendPackage(Package: array of Byte);
begin
FPackageComposer.AddArray(Package);
end;
procedure TConnectionManager.SendPackageReadyEvent(Sender: TObject;
Package: array of Byte);
begin
//
LogManager.WriteString("Written to Com");
LogManager.WriteByteArray(Package);
//
FCommPort.Write(Package, Length(Package));
end;
Те получив пакет я вызываю событие,FConnectionManagerPackageReceivedEvent
Там обрабатываю итд итп те в итоге все в Synchronize потоко будет.
А я терерь переделаю:
<След пост>
← →
Kolan © (2006-10-16 20:32) [114]Делаю форму:
TSynchronizationForm = class(TForm)
public
procedure SXPackageReady(var Msg: TMessage); message SX_PACKAGEREADY;
end;
Она - поле класса:TConnectionManager = class
private
***
FSynchronizationForm: TSynchronizationForm;
FPackage: TByteArray;
При получении пакета:procedure TConnectionManager.PackageReceivedEvent(Sender: TObject;
Package: array of Byte);
begin
SavePackage(Package);
PostMessage(FSynchronizationForm.Handle, SX_PACKAGEREADY,
Integer(Pointer(Self)), 0);
end;
При получении:procedure TSynchronizationForm.SXPackageReady(var Msg: TMessage);
begin
(Msg.WParam as TConnectionManager).SendPackage;
end;
Вотэто идея. Проверит не могу, так как не могу правильно сохранить указатель на TConnectionManager(в смысле на его экземпляр). А затем вызвать функцию..
Процедура сохранения пакета:procedure TConnectionManager.SavePackage(Package: array of Byte);
begin
Move(Package, FPackage, SizeOf(Package));
end;
← →
Kolan © (2006-10-16 20:32) [115]Как правильно это сделать(Подчеркнутое)?
← →
Leonid Troyanovsky © (2006-10-16 20:39) [116]
> Kolan © (16.10.06 20:01) [111]
> Но в денном случае, опираясь на ваш код. В
> Synchronize(ShowResult); мне надо лишь отправить пакет дальше.
> .. и Тут же вернуться. Те никаких исключений в потоке не
Если не нужна синхронизация (обработки пакета),
то поток может распределить блок нужного размера путем GetMem,
заполнить его данными и отправить его адрес (размер) путем
Post(Thread)Message главному потоку в форме WM_USER+x.
Главный же поток, по окончании обработки, удалит блок.
Можно и без сообщений, моделируя очередь посредством TThreadList.
Т.е., рабочий поток заполняет его адресами блоков, а главный поток
в Application.OnIdle его обрабатывает.
--
Regards, LVT.
← →
Kolan © (2006-10-16 20:44) [117]
> Если не нужна синхронизация (обработки пакета),
> то поток может распределить блок нужного размера путем GetMem,
>
> заполнить его данными и отправить его адрес (размер) путем
> Post(Thread)Message главному потоку в форме WM_USER+x.
> Главный же поток, по окончании обработки, удалит блок.
Дааа, может Можно и не через GetMem, Но сообщение прийдет в форму.
А обработанное должно быть в TConnectionManager, а от Формы до него ого го см[106]. Что бы это сотворить надо предавать хендл формы во все эти классы.
И еще форма узнает о том что существует какой-то поток, какие-то байты нафиг её это надо, её дело нажатия на кнопочки обработать...
← →
Kolan © (2006-10-16 20:46) [118]В жизни не создавал форм динамически, при
FSynchronizationForm := TSynchronizationForm.Create(nil);
получаю resourse TSynchronizationForm not found. Как избавится?
← →
Leonid Troyanovsky © (2006-10-16 20:58) [119]
> Kolan © (16.10.06 20:44) [117]
> А обработанное должно быть в TConnectionManager, а от Формы
> до него ого го см[106].
Ну, я так далеко не заглядывал :)
Сделай компонент, который, с одной стороны, будет лежать
на форме (и знать, как с ней взаимодействовать), а, с другой
стороны - создаст поток и тоже будет с ним взаимодействовать.
Если хочется, то можно снабдить компонент окном, на манер TTimer,
в которое и будет осуществляться PostMessage.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2006-10-16 21:02) [120]
> Kolan © (16.10.06 20:46) [118]
> получаю resourse TSynchronizationForm not found. Как избавится?
Создавай потомка TForm.
Или, если нужно окно (невидимое), а не форма - AllocateHwnd.
--
Regards, LVT.
Страницы: 1 2 3 4 вся ветка
Форум: "Основная";
Текущий архив: 2006.11.26;
Скачать: [xml.tar.bz2];
Память: 0.72 MB
Время: 0.047 c