Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Зависание системы при втором запуске плагина (С#)  (Прочитано 8999 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Al Al
Интересующийся

ru
Offline Offline

« : 15-08-2013 07:42 » 

Всем здравствуйте,

Я задавал аналогичный вопрос на stackoverflow, но, видимо, там мне помочь не в силах. Испытаю удачу здесь.

Пишу плагин для CAD/CAE-системы. Название ее писать не буду, скажу лишь, что нынешние владельцы - немцы, но писали ее индусы, со всеми вытекающими... Проблем за год работы с этой системой и ее API - было МОРЕ, но нынешняя обезоружила и надругалась надо мной.

Плагин пишу на C# .NET 4.0, использую VS 2010 sp1. Казалось бы, победа была близка, но тестирование показало, что после второго запуска плагина (т.е. уже когда плагин второй раз отработает), - система зависает и появляется окошко "Сервер занят...". Окошко это не убрать, система никак не реагирует, приходится убивать процесс.

Стал дебажить. Выяснил, что код кидает AccessViolationException. Важно: исключение возникает при втором запуске плагина! При первом запуске - все проходит отлично! Приведу пример кода:

Код: (C#)
public class TestClass : IDisposable
{
    private Session theSession;
    private UI theUI = UI.GetUI();
    private BlockDialog theDialog;
    ...

    public TestClass()
    {
        theSession = Session.GetSession();
        theDialog = theUI.CreateDialog(theDlxFileName); // исключение возникает в этой строке!
        theDialog.AddApplyHandler(ApplyCb);
        theDialog.AddOkHandler(OkCb);
        theDialog.AddUpdateHandler(UpdateCb);
        theDialog.AddInitializeHandler(InitializeCb);
        theDialog.AddDialogShownHandler(DialogShownCb);
    }

    public DialogResponse Show()
    {
        theDialog.Show();

        ...
    }

    public void Dispose()
    {
        ...
        theDialog.Dispose();
        ...
    }

    public SomeOtherFunction(...)
    {
        ...
        theSession...
        ...
    }

    ...
}

Как видно, исключение возникает при попытке создать диалоговое окно. Еще раз обращу внимание, что мне приходится использовать кривое API для создания плагина и Session, UI, BlockDialog - это не мои классы. Чуть расскажу об этих классах: Session - это основной класс, через него происходит вся работа с тем, что предоставляет CAE-система. Через UI происходит вся работа с... интерфейсом пользователя, это логично. Конструкторов этих классов (как, впрочем, и почти всех классов в предоставляемом API) - не существует. Подозреваю, что в них реализован сигнлтон, что, в принципе, тоже логично. И, чтобы получить доступ к текущему "сеансу" программы и ГУИ необходимо использовать конструкции вида:

Код:
UI theUI = UI.GetUI();
...
theSession = Session.GetSession();

Возвращаемся к проблеме. Как оказалось, исключение возникает не при создании диалога, а при получении экземпляра Session. То есть, в этой строке:

Код:
theSession = Session.GetSession();

Как видно из первого листинга, я не использую theSession в конструкторе, и первое что приходит в голову - убрать ее от греха подальше. Однако, эта переменная нужна мне в будущем.

Стал рыть глубже. Выяснил, кто именно кидает исключение. Оказалось, проперти ActiveSketch. Что странно, при первом запуске, после получения экземпляра сеанса, theSession.ActiveSketch == null, но при втором запуске плагина возникает исключение...

Что забавно, ни до, ни после, - никогда! - я не использую этот самый ActiveSketch... Видимо, он обиделся, и решил попортить мне жизнь.

Далее еще интереснее... В то время, пока я нахожусь в дебаге и в шоке, theSession.ActiveSketch успевает стать равным null. Как результат, если продолжить выполнение плагина, то он выполнится без проблем и CAE-система не зависнет.

Но далее еще интереснее... После второго (теперь успешного) выполнения плагина, я могу спокойно убрать все брейкпоинты и вновь запустить плагин. Что же в результате? А в результате - плагин спокойно и без проблем отрабатывает третий, четвертый, пятые разы... И система при этом не зависает.

Что делать? Как быть?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 15-08-2013 10:47 » 

Ну если всё так криво, то при запуске надо начать крутить цикл с небольшим Sleep, внутри которого в try...catch ловить и гасить исключения до тех пор, пока это свойство само по себе не превратится в null, после чего спокойной продолжать работу.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Al Al
Интересующийся

ru
Offline Offline

« Ответ #2 : 15-08-2013 10:50 » 

Этот вариант, "в лоб", был самым первым, какой смог придумать. Не помогло, к сожалению.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 15-08-2013 14:29 » 

Al Al, т.е. если это плагин, то вылетает вся система, и из плагина это не контролируется.

Тогда, видимо, плагин не завершает свою работу корректно - может какие-то ресурсы не освобождает. В C# это довольно легко сделать. Без знания интерфейсов системы и штатных протоколов взаимодействия плагина с системой тут советовать нечего.

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

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Al Al
Интересующийся

ru
Offline Offline

« Ответ #4 : 15-08-2013 15:08 » 

Dimka, виснет вся система и из плагина это не контролируется, все верно.

На другом форуме тоже подсказывают, что, возможно, ресурсы не освобождаются. Однако, моя совесть чиста... Другое дело, непонятно что творится в коде CAE-системы... С ней это в "порядке" вещей - мною уже было обнаружено 4 бага и, чтобы обойти их, нужно было либо писать костыли, либо дожидаться нового релиза от разработчиков...

По поводу другого, небольшого плагина: он есть. Вернее, их даже несколько. Но они все небольшие, и подобных проблем там не возникало. Этот же плагин куда больше предыдущих...

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

ru
Offline Offline

« Ответ #5 : 27-08-2013 16:53 » 

Проблема "разрешилась" путем переписывания кода на C++.

Кажется, все-таки, баг был в .NET-либах API системы.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 27-08-2013 22:07 » 

Al Al, можно использовать C++.NET: взаимодействие оставить в native-коде, всё остальное - в CLR-коде.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Al Al
Интересующийся

ru
Offline Offline

« Ответ #7 : 28-08-2013 06:28 » 

Dimka, я думал об этом, но решил переписать все на чистый C++. Как результат - избавился от бага и производительность возросла. Не берусь сказать на сколько, не засекал время выполнения, но "на глаз" - код на C++ выполняется раза в 3 быстрее...

Раз уж написал, то спрошу заодно Улыбаюсь
Я дизассемблировал .NET-либы и они целиком и полностью состоят из DllImport'ов к функциям на Си (да, именно на Си, то есть, получается, еще один слой до C++-кода). То есть, получается, именно эти DllImport'ы так тормозят работу?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 28-08-2013 07:29 » 

Цитата: Al Al
"на глаз" - код на C++ выполняется раза в 3 быстрее...
Обычно это означает неумение писать и учитывать ньюансы. Native C++ быстрее CLR только в области интенсивных вычислений, где преобладает арифметика в больших циклах. Работа со структурами объектов (где много обращений через указатели) происходит с одинаковой скоростью.

Цитата: Al Al
Я дизассемблировал .NET-либы и они целиком и полностью состоят из DllImport'ов к функциям на Си (да, именно на Си, то есть, получается, еще один слой до C++-кода). То есть, получается, именно эти DllImport'ы так тормозят работу?
Зависит от сигнатуры. Но, как правило, если есть marshalling строк и структур между managed и unmanaged кодом, а также callback-функции упаковываются в делегаты, конечно, будут накладные расходы, потому что эти строки и структуры на каждый чих дублируются - одна копия находится под управлением сборщика мусора CLR, вторая в неуправляемом коде. Да и сам вызов импортируемой функции - это как вызов виртуальной функции объекта (через указатель).
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines