Транзакция в новом потоке

Автор Тема: Транзакция в новом потоке  (Прочитано 7892 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Здравствуйте. У меня в программе запускается длительная операция, в которой выполняются многочисленные обращения к БД Автокада для получения и создания объектов. Чтобы не блокировать все приложение, я запустил ее в отдельном таске. При этом если в процессе расчета какая-то транзакция завершается без вызова Commit(), то есть при явном или неявном вызове Abort(), то выбрасывается исключение: System.AccessViolationException: 'Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.'. Пример кода который его инициирует:
Код - C# [Выбрать]
  1. Task.Run(() =>
  2. {
  3.      var trans = bd.TransactionManager.StartTransaction();
  4.      trans.Abort();
  5.      trans.Dispose();
  6. });
Причем исключение возникает в основном UI потоке Автокада, и приложение завершается. Если во всех транзакциях выполнен вызов Commit(), то регулярной ошибки нет, но тем не менее время от времени она возникает в разных местах, то есть проблема не ушла. Подскажите, возможно вообще работать с базой Автокада в нескольких потоках, и если да, то как правильно это делать?

Отмечено как Решение Андрей Миков 06-05-2020, 21:26:09

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Re: Транзакция в новом потоке
« Ответ #1 : 05-05-2020, 20:52:47 »
Попробуйте так:
1. При запуске плагина (до инициализации окон) положите в статическую переменную текущий Dispatcher
2. Внутри вашей длительной задачи все обращения к БД автокада выполняйте внутри этого Dispatcher.
Что-то типа того:
Код - C# [Выбрать]
  1. public void Invoke(Action doAction)
  2. {
  3.     try
  4.     {
  5.         if (doAction != null)
  6.         {
  7.             _currentDispatcher?.Invoke(doAction);
  8.         }
  9.     }
  10.     catch (Exception exception)
  11.     {
  12.         // отображение, логирование или еще что
  13.     }
  14. }
  15. ...
  16.  
  17. _mainThreadEvent.Invoke(() =>
  18. {
  19.     // работа с БД
  20. });
  21.  

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Транзакция в новом потоке
« Ответ #2 : 05-05-2020, 22:22:25 »
Подскажите, возможно вообще работать с базой Автокада в нескольких потоках, и если да, то как правильно это делать?
Нельзя. Только из главного потока. Точка.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Re: Транзакция в новом потоке
« Ответ #4 : 06-05-2020, 13:42:00 »
Александр Пекшев aka Modis, спасибо, в Dispatcher основного потока все методы отлично работают.
https://adn-cis.org/ispolzovanie-potokov-dlya-fonovoj-obrabotki.html
Пример интересный, но создание контрола для запуска процесса в основном потоке похоже на хак. Может быть сделать пример с Dispatcher? И использовать таск вместо создания потока руками.
Еще есть вопрос - можно ли во вторичных потоках создавать объекты автокада, или через конструктор, или через вызов методов Clone, Offset и др, а затем в основном потоке открыть транзакцию и добавить их в базу? Это корректно?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Транзакция в новом потоке
« Ответ #5 : 06-05-2020, 13:47:26 »
создание контрола для запуска процесса в основном потоке похоже на хак.
Это рекомендация от ADN DevHelp. Так что использование допустимо.
Еще есть вопрос - можно ли во вторичных потоках создавать объекты автокада, или через конструктор, или через вызов методов Clone, Offset и др, а затем в основном потоке открыть транзакцию и добавить их в базу? Это корректно?
Нет. Это всё чревато спонтанными аварийными завершениями AutoCAD...
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Транзакция в новом потоке
« Ответ #6 : 06-05-2020, 15:20:34 »
У меня в программе запускается длительная операция, в которой выполняются многочисленные обращения к БД Автокада для получения и создания объектов. Чтобы не блокировать все приложение, я запустил ее в отдельном таске.

1. Для изменения БД, тебе в любом случае придется блокировать документ.
2. Даже если подумать логически, не стоит давать пользователю делать что-то во время изменения БД, т.к. пользователь под этим может подразумевать открытие документов, переключение на другие документы, удаление объектов. Пусть ждет.
3. Autocad использует ядро ACIS (https://en.wikipedia.org/wiki/ACIS)
Скорее всего, разработчики ядра не предусмотрели параллельную работу из различных потоков. Упоминание об ограничении есть в документации Autodesk. На форумах были попытки работы с API из различных потоках, но ни к чему не привели. Не имеет смысла тратить время, чтобы убедиться, что это не работает.

Если операция длительная
Вставь progressbar.
https://through-the-interface.typepad.com/through_the_interface/2007/05/displaying_a_pr.html
Можешь добавить возможность прервать процесс. (Если очень долгий процесс.)
https://adn-cis.org/kak-pozvolit-polzovatelyu-prervat-dlitelnuyu-operacziyu-v-autocad-.net.html

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Re: Транзакция в новом потоке
« Ответ #7 : 06-05-2020, 17:28:55 »
Я бы подумал про изменение логики работы программы.
Когда программа работает долго, то для оптимизации я стараюсь разделить "бизнес логику" и вывод результата работы. Обсчитывать "бизнес логику", построенную на своих объектах и классах можно в многопоточном режиме и потом собрав все в кучу вывести результат одним потоком.
Сам по себе вывод большего количества примитивов или изменение примитивов происходит быстро, ну не миллионами же Вы их меняете. Может и Вам стоит сначала собрать и подготовить все данные, а потом пакетом вывести в файл.

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Re: Транзакция в новом потоке
« Ответ #8 : 06-05-2020, 18:03:12 »
Даже если подумать логически, не стоит давать пользователю делать что-то во время изменения БД
Да, есть риск что пользователь что-то удалит и весь расчет упадет  :(
Скорее всего, разработчики ядра не предусмотрели параллельную работу из различных потоков
Сейчас, когда даже в телефонах стоят многоядерные процессоры, это особенно печалит...
Вставь progressbar.
Это именно то что я собирался сделать. Спасибо за пример, я и не знал что есть готовый прогрессбар - ProgressMeter. Правда очень уж куцый он, ни процент вывести, ни оставшееся время. И почему-то затирается строкой состояния при обновлении экрана. Есть какой то ProgressTrayItem, может быть по нему есть пример, не нашел его в документации.
Я бы подумал про изменение логики работы программы.
В том то и дело что бизнес логика содержит создание объектов автокада - как промежуточных, для расчета, так и окончательных для добавления в базу. И разделить их не получится.

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

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Транзакция в новом потоке
« Ответ #9 : 06-05-2020, 18:25:22 »
Правда очень уж куцый он, ни процент вывести, ни оставшееся время.
Про процент не понял, т.к. именно процент он и выводит, плюс заголовок.
Если у тебя несколько последовательных действий, то можешь вновь создать его с новым заголовком, так повысишь информативность:
pm.Start("Подготовка данных");
....
pm.Start("Расчет");
...
pm.Start("Вывод результата");
..может и от обновления экрана поможет.


ну и все как в примере, сначала pm.Start(), затем pm.SetLimit(499);  т.к. pm.Start() сбросит лимит.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Re: Транзакция в новом потоке
« Ответ #10 : 06-05-2020, 18:34:04 »
бизнес логика содержит создание объектов автокада - как промежуточных, для расчета,
Вот от этого я и предлагаю отказаться. Вы видимо пытаетесь что то решить геометрическими построениями, что влечет за собой огромные накладные расходы, может стоит посмотреть и поискать аналитические решения, это точно будет быстрее и можно будет параллелить.

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Re: Транзакция в новом потоке
« Ответ #11 : 06-05-2020, 19:18:30 »
Про процент не понял, т.к. именно процент он и выводит, плюс заголовок.
я имел ввиду вывод процента в виде числа, плюс вывод оставшегося времени выполнения, этапа
Если у тебя несколько последовательных действий, то можешь вновь создать его с новым заголовком, так повысишь информативность:
и заголовок не меняется, даже при UpdateScreen, только созданием нового прогрессбара можно новый установить
Вот от этого я и предлагаю отказаться.
да, использование другого решения снимет эту проблему, особенно принимая во внимание случаи некорректной работы методов автокада. Останавливает то что на поиск и использование нового решения потребуется время....

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Транзакция в новом потоке
« Ответ #12 : 06-05-2020, 20:23:10 »
Цитата: Привалов Дмитрий от 06-05-2020, 18:25:22

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

я имел ввиду вывод процента в виде числа, плюс вывод оставшегося времени выполнения, этапа
Цитата: Привалов Дмитрий от 06-05-2020, 18:25:22

    Если у тебя несколько последовательных действий, то можешь вновь создать его с новым заголовком, так повысишь информативность:

и заголовок не меняется, даже при UpdateScreen, только созданием нового прогрессбара можно новый установить
Это стандартный Progressbar, который использует сам AutoCAD. Если тебя не устраивает стандартный, то можешь создать свой (например, немодальная форма).

Останавливает то что на поиск и использование нового решения потребуется время....
Вполне возможно, что это решение уже найдено и тебе на форуме подскажут. Главное не стесняться задавать вопросы.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Re: Транзакция в новом потоке
« Ответ #13 : 06-05-2020, 21:25:44 »
Хорошо. Спасибо за помощь!

Оффлайн Андрей МиковАвтор темы

  • ADN OPEN
  • Сообщений: 7
  • Карма: 0
Re: Транзакция в новом потоке
« Ответ #14 : 06-05-2020, 21:51:21 »
Александр, еще вопрос: вообще, безотносительно потоков, возможно создание объектов автокада вне транзакции? с последующим добавлением их в транзакцию или освобождением через Dispose. Или это тоже чревато?