Выполнение многопоточных заданий внутри плагина AutoCAD .Net

Я знаю, что API-интерфейсы Autocad не должны вызываться/использоваться в многопоточности. Но как насчет выполнения многопоточного задания (в подключаемом модуле Autocad .Net), которое не требует каких-либо конкретных вызовов/типов Autocad?

Ситуация такова: 1. некоторые полилинии САПР извлекаются через API, их интересующие свойства заворачиваются в пользовательские типы, а затем 2. в другом слое выполняются некоторые многопоточные вычисления для этих пользовательских типов. 3. Пользовательские типы приложений записывают свои результаты обратно в полилинии САПР через API Autocad.

Только второй шаг выполняется в многопоточном режиме.

Приложение использует метод StartTransaction() для получения объекта Transaction. У меня не было ни одного сбоя за многие годы. Но теперь я пытаюсь использовать StratOpenCloseTransasction(), он много раз падает. В частности, он падает, когда вызывается Editor.Rengen(), поскольку я думаю, что он проходит через каждый объект в базе данных и, возможно, некоторые из них повреждены. Я сузил проблему, и одной из причин, по-видимому, является многопоточность.

Есть ли причина, по которой CAD должен давать сбой при вызове многопоточности, хотя API-интерфейсы не задействованы? Безопасно ли использовать многопоточность таким образом? Обрабатывает ли StartTransaction() объекты лучше, чем StartOpenCloseTransaction, с точки зрения их удаления? Поскольку у меня не было сбоев на этом.

Большое спасибо


person ali    schedule 29.08.2015    source источник
comment
Я только что столкнулся с некоторыми ошибками на Editor.Regen. Это произошло из-за переходных сущностей.   -  person Maxence    schedule 02.09.2015
comment
Что ты имеешь в виду под временными сущностями, Максенс?   -  person ali    schedule 03.09.2015
comment
Временные объекты — это временные объекты (не связанные с базой данных), нарисованные с помощью класса TransientManager. Примером таких сущностей является куб представления. Во время регенерации эти объекты обновляются. TransientManager может работать только с активным документом. Возможно, при вашей фоновой обработке AutoCAD путается с активным документом.   -  person Maxence    schedule 03.09.2015
comment
@Maxence Большое спасибо за подсказку. Я не использую временные объекты. В конце я не смог/не докопался до сути и изменил его на метод StartTransaction, как вы тоже предложили. По какой-то причине использование метода StartOpenCloseTransaction для вставки объектов исказило их цвета на чертеже, как будто они больше не являются допустимыми объектами. Я думаю, именно поэтому Реген выдавал исключение. Я никогда не сталкивался с этим с StartTransaction годами.   -  person ali    schedule 04.09.2015


Ответы (2)


Большой проблемой многопоточности является синхронизация с основным потоком (потоком AutoCAD). Конечно, при условии, что вы не передаете какой-либо тип/данные/объект AutoCAD в другой поток (только чистые данные .NET/C++).

Зная о рисках, вы можете выполнить синхронизацию с помощью подхода, описанного в этом PDF-файле: http://aucache.autodesk.com/au2011/sessions/2526/class_handouts/v1_CP2526_Taget.pdf

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

bool isQuiescent(AcApDocument* pDoc = curDoc())
{
return ( (pDoc != NULL)
 && pDoc->isQuiescent()
 && ((pDoc->lockMode() == AcAp::kNotLocked) ||
 (pDoc->lockMode() == AcAp::kNone))
 && (acedCommandActive() == 0) // no script or lisp is active
 && (acDocManager != NULL)
 && (acDocManager->inputPending(pDoc) == 0)
 && (::GetInputState() == 0)
 );
}
person Augusto Goncalves    schedule 29.08.2015
comment
Этот пример кода в этом документе нереалистичен. Я не вижу, чтобы пользователь запускал команду, затем продолжал работать, пока обработка выполняется в фоновом режиме, и вдруг вижу, что на его рисунке появляются объекты! Что я делаю в этой ситуации, так это отображаю уведомление, а затем обрабатываю результат вычисления, когда пользователь щелкает ссылку в пузыре уведомления. команда IMPORTIGES работает так. - person Maxence; 29.08.2015
comment
Спасибо за ссылку. Знаете ли вы, должен ли этот фрагмент кода и регистрация/обработка оконного сообщения быть на С++, а затем вызываться на С#? Или мы можем просто выполнить описанную выше проверку на С# и, если она верна, сделать вывод, что можно безопасно вызывать API-интерфейсы САПР в основном потоке. - person ali; 29.08.2015
comment
этот код должен сообщать вам, когда AutoCAD готов принимать ответные звонки. ссылка PDF должна содержать более подробную информацию. - person Augusto Goncalves; 31.08.2015
comment
В управляемом API AutoCAD есть свойство Application.IsQuiescent. Не уверен, что это эквивалентно этому коду C++. Существует также свойство Editor.IsQuiescent. - person Maxence; 01.09.2015

Почему вы используете StartOpenCloseTransaction? Есть небольшой прирост производительности, но стандартные транзакции более безопасны. Проблема с OpenCloseTransaction в том, что никто точно не знает, как это работает. Единственная документация:

ведет себя аналогично объекту Transaction, который заключает в себе методы Open и Close объекта, упрощая закрытие всех открытых объектов вместо того, чтобы явно закрывать каждый открытый объект. Рекомендуется для использования в вспомогательных или служебных функциях, которые могут вызываться неизвестное количество раз, и использоваться при работе с большинством обработчиков событий.

что то не очень понятно...

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

person Maxence    schedule 29.08.2015
comment
Спасибо за Ваш ответ. Вопрос, размещенный в приведенной ниже ссылке, заключается в том, почему я использовал StartOpenCloseTransaction. - person ali; 29.08.2015
comment
forums.autodesk.com/ т5/нетто/ - person ali; 29.08.2015
comment
Если вы находитесь вне процесса, сортировка ваших вызовов из вашего приложения в AutoCAD замедлит работу вашего приложения больше, чем использование нескольких транзакций. Вам нужен массивный интерфейс. - person Maxence; 29.08.2015
comment
Ну, я использовал StartTransaction коротким способом: передавая все объекты и фиксируя транзакцию за один раз (если это то, что это значит). - person ali; 29.08.2015
comment
Когда вы говорите, что стандартная транзакция более безопасна (под чем, я полагаю, вы подразумеваете метод StartTransaction()), есть ли какие-либо доказательства/доказательства/причина для этого? - person ali; 29.08.2015
comment
Как минимум два: транзакции OpenClose не могут быть вложенными и к ним нельзя обращаться через Database.TransactionManager.TopTransaction (также нельзя использовать ObjectId.GetObject, что является удобным способом открытия объекта). Вместо безопасного я должен был использовать слово удобный. - person Maxence; 29.08.2015