Утилизация COM в многопоточной среде - PullRequest
4 голосов
/ 14 июля 2011

Я пытаюсь правильно утилизировать устаревший COM-элемент управления VFP (FoxPro), завернутый в RCW, сгенерированный Visual Studio.Элемент управления предоставляет метод Destroy, который я должен вызвать, чтобы позволить элементу управления должным образом разрушиться.Существует очень высокая вероятность того, что метод элемента управления может выполняться в фоновом потоке, когда сделан запрос на удаление экземпляра COM.VFP - это модель однопотоковой квартиры, поэтому при вызове Destroy его просто нужно добавить в стек выполнения VFP.

В идеале вызов Destroy будет правильным решением, поскольку он позволяет экземпляру COM очищать некоторые компоненты.Ресурсы.Меня беспокоит то, что создание экземпляра COM-элемента управления VFP фактически запускает экземпляр среды выполнения языка VFP, в котором находится этот элемент управления, и этот экземпляр может быть заблокирован (без ответа).Этот COM-компонент предоставляет функциональные возможности в крупном корпоративном 20-летнем устаревшем приложении, и я видел ситуации, когда поток .NET, пытающийся вызвать метод для этого элемента управления, просто блокируется, не выдавая ошибку (всегда вызванную ошибками в устаревшемКод VFP).Это случается не часто, но достаточно часто, чтобы он побудил меня создать менеджер экземпляров, который запускает методы на экземпляре COM VFP в фоновом потоке и периодически проверяет, заблокирован ли этот поток, и, если да, уничтожаетЭкземпляр COM и поток и перезапуск нового экземпляра для мониторинга.

Является ли это правильным способом избавиться от потока, в котором может выполняться фоновый метод?

Должен ли я попытаться получить фантазию с помощьюпытается вызвать метод Destroy, чтобы позволить элементу управления COM корректно завершить работу?

if (_vfpThread != null)
{
  try
  {
    if (_vfpThread.IsAlive)
      _vfpThread.Abort();
  }
  catch (ThreadAbortException)
  { }
  finally
  {
    _vfpThread = null;
  }
}

if (_vfpInstance != null)
{
  Marshal.ReleaseComObject(_vfpInstance);
  _vfpInstance = null;
}

Ответы [ 2 ]

4 голосов
/ 14 июля 2011

Когда вызов метода находится в ожидании для COM-объекта на основе VFP (который всегда выполняется в квартире STA), вызов любого метода в этом же COM-объекте из другого потока будет блокироваться до тех пор, пока предыдущий вызов не вернется(выходит из квартиры).Это означает, что любой поток, пытающийся вызвать Destroy () одновременно, будет зависеть от этого первого потока.И если этот поток не знает, чтобы выйти добровольно, он теоретически может держать поток удаления заблокированным на неопределенный срок.Итак, другими словами, нет прямого способа попросить 1-й поток немедленно выйти из метода, вызвав другой метод в COM-объекте из другого потока.Вызов _vfpThread.Abort () должен работать, но безопасность этого подхода во многом зависит от внутренних особенностей класса VFP.Во многих случаях из-за того, что он является устаревшим кодом, он не будет иметь ничего общего с разделом try / catch / finally, который позволил бы обеспечить плавный выход, поэтому ресурсы могут остаться незамеченными.- ПЛОХО!

Другой подход - установить где-нибудь внешний флаг (реестр, файл и т. Д.), Который будет доступен для чтения этим первым потоком из метода, который он выполняет.Это, конечно, требует, чтобы класс VFP знал о необходимости считывать флаг из каждого из своих опубликованных COM-методов и действовать соответствующим образом и быстро.

Кроме того, в отношении вашего фрагмента кода.Перехват ThreadAbortException в коде, который прерывает поток, имеет смысл только в том случае, если поток, выполняющий этот код, прерывает сам себя.Что было бы довольно неловко, поскольку вместо этого он мог просто вернуться из метода.(Или этот поток, который вызывает _vfpThread.Abort (), также потенциально может быть прерван из еще одного потока?) В обычном сценарии то, что вам нужно заключить в ловушку ThreadAbortException, является основным кодом 1-го потока, который выполняет вызовы для всехэти бизнес-методы на объекте COM.В идеале это должно быть так же глубоко в стеке, как и у самих методов VFP, когда код сможет корректно закрыть все ресурсы / таблицы и т. Д. Перед повторным вызовом исключения.И затем в основном методе, который вы передали ThreadStart, у вас будет похожий перехватчик, за исключением того, что он мирно вернется из метода, тем самым завершив поток или выпустив его в пул потоков.

0 голосов
/ 14 июля 2011

Да, я правильно понял ваш код. - Спасибо.

Отключение потока vfp, если он не завершается корректно в течение 60 секунд, возможно, единственное, что вы можете сделать. С точки зрения того, что должен делать Dispose - он должен стараться изо всех сил высвобождать все неуправляемые ресурсы, которые, к сожалению, скрыты от этого кода, поскольку они используются / открываются из класса VFP COM. Таким образом, если COM-объект захвачен, основной поток не сможет заставить его освободить эти ресурсы. Возможно, вы могли бы попытаться обернуть все тело бизнес-метода COM в блок try-catch VFP и освободить ресурсы / закрывающие таблицы в секции catch. Есть большая вероятность, что блок try-catch перехватит исключение ThreadAbortException, вызванное вызовом _vfpThread.Abort () из основного потока.

...