Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2014.07.20;
Скачать: [xml.tar.bz2];

Вниз

Работа с плагинами   Найти похожие ветки 

 
dreamse ©   (2012-01-20 02:51) [0]

Приветствую.

В виде плагинов использую обычные DLL c набором функций:

1) имя, версия и пр.
2) функция старта (тут обычно в плагине запускается отдельный поток со своим функционалом)
3) Функция передачи команды в плагин
4) Функция получения данных из плагина

Схема очень простая, примеров в сети кучи. Если нужно приведу листинг.

Все работает, но возникли проблемы при расширении, т.е плагинов уже много и функционал растет.

Проблема в том что если возникает критическая ошибка в одном из плагинов - падает все приложение (почему то вспомнил miranda которая падает через раз :) )

Как можно защитить приложение от падения ? в идеале - переодически опрашивать плагины и выгружать те которые не отвечают (либо перезапускать)


 
Дмитрий Белькевич   (2012-01-20 14:14) [1]

DLL - это dynamic linked library, после линковки дллка - это фактически кусок вашего экзешника. Если критическая ошибка возникает в дллке - считайте, что критическая ошибка возникает в куске экзешника.

Что делать:

1. Искать ошибки и их устранять.
2. Выполнить плагины в виде отдельных процессов.


 
dreamse ©   (2012-01-20 14:49) [2]

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

Есть ли какой то способ глобально поймать ошибку в dll и либо заблокировать ее try except либо выгрузить dll в которой произошла ошибка ?


 
icWasya ©   (2012-01-20 16:08) [3]

поскольку у каждой DLL свой менеджер памяти и своя RTTI  и вследствии чего передавать объекты, в том числе и наследники TException между модулями настоятельно не рекомендуется, то прокатят только административные методы, типа а) внутри плагина не должно возбужнаться исключение; б) если таковые возникают, то перехватывать внутри функции плагина и превращать их во вменяемые код ошибки в) если это не выполняется, сильно бить по рукам разработчиков плагинов .

Можно ещё посмотреть в сторону safecall


 
Дмитрий Белькевич   (2012-01-20 16:23) [4]

1. Бить по руками и заставлять ловить блоками try.
2. Смотреть в сторону IPC.


 
Dimka Maslov ©   (2012-01-20 19:26) [5]


> icWasya ©   (20.01.12 16:08) [3]


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


>
> Как можно защитить приложение от падения


Код вызова функций из плагина обернуть в try..except. При словленном исключений - банить плагин навсегда. Впрочем от сильно глобального сбоя это может и не прокатить.


 
dreamse ©   (2012-01-20 21:47) [6]

Нашел баг который рушит всю систему.

Это обращение к уже удаленному объекту (Free)

если эта ошибка происходит в обычном приложении то появляется лишь диалог с ошибкой (access violation) и можно закрыв дальше работать.

Если эта же ошибка возниает в плагине (dll) то она сразу выбивает и рушит все приложени.

Вот что странно.


 
dreamse ©   (2012-01-20 22:05) [7]

В чем еще проблема.

В DLL запускаются потоки.
И если их основного приложения выгрузить DLL методом FreeLibrary все данные уничтожаются а потоки продолжают работать неокторое время, обращатся к уже уничтоженным данным и генерировать исключения.

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

пробывал FreeLibraryAndExitThread

http://www.vsokovikov.narod.ru/New_MSDN_API/DLL/fn_freelibraryandexitthread.htm

Тоже самое, потоки продолжают работать.

Есть ли решение по правельной выгрузки загруженной DLL ?


 
Inovet ©   (2012-01-21 00:22) [8]

> [7] dreamse ©   (20.01.12 22:05)
> Есть ли решение по правельной выгрузки загруженной DLL ?

Подать знак потокам и дождаться их завершения в функции ДЛЛ DllEntryPoint


 
Leonid Troyanovsky ©   (2012-01-21 11:26) [9]


> Inovet ©   (21.01.12 00:22) [8]

> Подать знак потокам и дождаться их завершения в функции
> ДЛЛ DllEntryPoint

Нельзя там ожидать.

http://msdn.microsoft.com/en-us/windows/hardware/gg487379.aspx

--
Regards, LVT.


 
Inovet ©   (2012-01-21 13:01) [10]

> [9] Leonid Troyanovsky ©   (21.01.12 11:26)
> Нельзя там ожидать.

Хм. Ну, если так, то тогда остаётся написать специальную функцию для остановки потоков, и вызывать её перед выгрузкой ДЛЛ.


 
Dimka Maslov ©   (2012-01-21 14:28) [11]

Ну надо было начинать с того, что там есть потоки. С потоками всё гораздо сложнее. Предлагаемое решение - каждый поток должен время от времени проверять общий флаг завершения и немедленно прекращать работу при его выставлении. Другое дело, что плагины может разрабатывать кто угодно... Как-то я разговаривал с разработчиками одной проги. У них была возможность подключения плагинов и расширения функционала третьми лицами. Потом они отказались. Почему? А потому-что вопросы пользователей по глакам плагинов адресовались им, не разработчикам плагинов. Когда это надоело, лавочка прикрылась.


 
dreamse ©   (2012-01-21 17:23) [12]

В общем проблема с глючным плагином решилась. Не без помощи данного форума должен заметить.

В общем:

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

1. Старатся по возможности не использовать в dll потоки
2 Если использование потоков все таки необходимо то

Отслеживать выгрузку DLL плагина:


procedure DLLEntryPoint(dwReason: DWord);
begin
 case dwReason of
   //DLL_PROCESS_ATTACH:
   DLL_PROCESS_DETACH:
     begin
       if assigned(dmMod) then
         begin
           TerminateThread ...
         end;
     end;
 end;
end;

 DllProc := @DLLEntryPoint;
 DllEntryPoint(Dll_Process_Attach);



где в DLL_PROCESS_DETACH: убивать все созданные потоки.

3. Не использовать в коде функцию sleep. вообще!
Если нужна задержка воспользоватся таймером (либо c TDataModule либо создать временный таймер - нужно создавать свое окно.)

Проблема в SLEEP очень простая  - если пока идет задержка (в данном коде это было в компоненте расположенном на TDataModule) выгрузить библиотеку то после sleep будет выполнен дальше код - который обратится к уже уничтоженному объекту.

-----

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


 
dreamse ©   (2012-01-21 17:26) [13]

> Inovet ©   (21.01.12 13:01) [10]

Лучше как показал в предыдущем примере. Так будет правельней отслеживать выгрузку.


 
Inovet ©   (2012-01-21 17:39) [14]

> [13] dreamse ©   (21.01.12 17:26)
> Лучше как показал в предыдущем примере. Так будет правельней
> отслеживать выгрузку.

Я не говорил про "убивать потоки".
Поток должен сам корректно завершиться. Для этого надо выставить флаг завершения, который поток периодически проверяет и завершается при его поднятии. т.е.
TerminateThread
принудительно завершит поток, а флаг только сообщит ему о необходимости завершения. Далее
WaitForSingleObject
но вот сказали, что нельзя ждать в
DLLEntryPoint


 
Дмитрий Белькевич   (2012-01-21 20:25) [15]


>  после sleep будет выполнен дальше код - который обратится
> к уже уничтоженному объекту.


Если объект уничтожен и обнилен - можно попробовать сделать проверку на Assigned.


 
Dimka Maslov ©   (2012-01-21 21:21) [16]


> В принципе текущая проблема решилась, осталось придумать
> как сделать глобальную обработку ошибок именно в DLL чтобы
> не падало все приложение из за кривых рук разработчиков.
>


Тут можно посоветовать разбить своё приложение на два отдельных процесса, один из которых управляет плагинами и тесно взаимодействует с основным. При падении процесса, ответственного за плагины, он возобновляется.


 
dreamse ©   (2012-01-21 23:22) [17]

>  При падении процесса, ответственного за плагины, он возобновляется.

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

> Если объект уничтожен и обнилен - можно попробовать сделать проверку на Assigned.

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

> Поток должен сам корректно завершиться.

Логически это верно.
Другое дело что если в этот момент попытатся завершить работу windows - винда сообщает что тот или иной процес не отвечает ( так как ждет когда же поток очнется) так что в этом случае удобней убивать поток.


 
Inovet ©   (2012-01-21 23:37) [18]

> [17] dreamse ©   (21.01.12 23:22)
> Другое дело что если в этот момент попытатся завершить работу
> windows - винда сообщает что тот или иной процес не отвечает
> ( так как ждет когда же поток очнется) так что в этом случае
> удобней убивать поток.

Этот случай отдельно обрабатывать.


 
Inovet ©   (2012-01-21 23:39) [19]

Ты компьютер тоже отключаешь выдиранием вилки из розетки? Вот и потоки завершай штатно, а не прибиванием. Вроде это очевидно.


 
Дмитрий Белькевич   (2012-01-22 11:11) [20]


> Другое дело что если в этот момент попытатся завершить работу
> windows - винда сообщает что тот или иной процес не отвечает
> ( так как ждет когда же поток очнется) так что в этом случае
> удобней убивать поток.


Sleep"ы лучше в потоках вообще не использовать, но уже сам убрал и хорошо - туда и дорога.
Усыплять потоки удобнее TEvent"ами:


FTerminateEvent: TEvent;



procedure TDICOMStoreQueue.StartAndTerminate;
begin
....
FSession.Terminate;
FTerminateEvent.SetEvent;



constructor TSCUStoreSessionQueue.Create(AOwner: TDICOMStoreQueue);
begin
...
FTerminateEvent := TEvent.Create(nil, True, False, "");



destructor TSCUStoreSessionQueue.Destroy;
begin
...
FreeAndNil(FTerminateEvent);


Собственно, сама замена slee"а:


FTerminateEvent.WaitFor(Owner.FTimeDelay);


Так можно поток присыпить как sleep"ом, при этом можно его "снаружи" запустить и остановить в любой момент перед закрытием приложения.
Event"ов может быть несколько.


>  ( так как ждет когда же поток очнется)


Не нужно ожидать просыпания потоков, нужно их заставлять останавливаться.

Глобально: разобраться с работой с потоками. Не всё там просто. Но - сделать можно. Сами на точно такие же грабли с потоками наступали:

http://delphimaster.net/view/1-1302154341/



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2014.07.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.004 c
2-1379322318
Никита2013
2013-09-16 13:05
2014.07.20
Блокировка спящего режима Андроид


15-1387384044
Kerk
2013-12-18 20:27
2014.07.20
DelphiSpec


2-1379405814
TInteger
2013-09-17 12:16
2014.07.20
Как использовать потоки для быстрого чтения текстового файла?


3-1300045896
andrey-alekceevich
2011-03-13 22:51
2014.07.20
фильтрация полей формата дата/время


15-1388121833
Jeer
2013-12-27 09:23
2014.07.20
Все - дед!





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский