Вызов неуправляемого класса C ++ с сохранением состояния из веб-службы ASP.NET - PullRequest
4 голосов
/ 08 декабря 2010

Я унаследовал наполовину завершенное приложение, которое, похоже, использует модель, которая, я не уверен, может надежно работать.

Это веб-служба ASP.NET, которая при каждом вызове загружает неуправляемый C ++ .DLLиспользуя

[DllImport ( "kernel32.dll" , EntryPoint = "LoadLibraryA" )]
public static extern int LoadLibrary( string lpLibFileName );

, а затем совершает несколько вызовов к нему, например,

 [DllImport(@"MyUnamanagedDLL.dll")]
 public static extern string DoStuff( );

В неуправляемом C ++ .dll он использует одноэлементный режим для удержания состояния между вызовами.Это так, что он должен только инициализироваться один раз и загружать кучу медленных вещей с диска и базы данных, а не при каждом вызове веб-службы, поскольку это слишком медленно.

Таким образом, каждый вызов в неуправляемый .dll сначала вызывает Getinstance() Если экземпляр имеет значение null, он инициализирует его и перезагружает все, если нет, он предполагает, что он готов к работе.

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

Является ли эта модель вообще надежной?Можете ли вы убедиться, что если веб-служба выключена, то неуправляемое состояние очищается правильно?Можете ли вы убедиться, что вы получите надежный одноэлементный экземпляр между вызовами loadlibrary?

Ответы [ 4 ]

1 голос
/ 08 декабря 2010

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

Ответ зависит от нескольких вещей;в первую очередь: что это за государство?Если вы смотрите на вещи, за которые ядро ​​несет основную ответственность - память, файловые дескрипторы, HWND - тогда вы можете ожидать, что ядро ​​очистится, когда библиотека выгружена , всякий раз, когдаis («[Я] золотой компоновщик, я часто намеренно опускал деструкторы, потому что многие структуры данных живут для жизни программы; в таком случае деструкторы служат только для замедления выхода из программы»; да, я знаю золотокомпоновщик не работает в Windows, но принцип все еще применяется).

Если вы говорите о чем-то, что не гарантируется ядром, то я бы порекомендовал предоставить функцию DllMain, которая обрабатывает PROCESS_DETACH сообщение для обработки любой необходимой выгрузки.

Можете ли вы гарантировать, что вы получите надежный одноэлементный экземпляр между вызовами loadlibrary?

Простые случаи:

  • Singleton не существует
  • Процесс A нуждается в Singleton, создает и использует его
  • Процесс B нуждается в Singleton, sон уже существует, использует его
  • процессам A и B больше не нужен синглтон, он очищен
  • синглтон не существует
  • процессу C нужен синглтон, он создает и использует его
  • ...

Более сложный случай связан с условиями гонки при создании или очистке:

  • синглтона не существует
  • Процесс А нуждается в синглтоне, начинает его создавать
  • До завершения процесса А процесс В нуждается в синглтоне, создает его;это проблема
  • Процессы A и B больше не нуждаются в синглтоне, начните его очищать
  • Перед очисткой синглтона, процесс C нуждается в нем, видит, что он существует, и пытается использовать его;это проблема

Это классические условия гонки, и решение состоит в том, чтобы убедиться, что шаг проверки / создания (и проверки / очистки) являются атомарными.Не увлекайсяИспользуйте атомный подсчет ссылок или Mutex es


Для записи;Я не фанат такого рода архитектуры (синглтоны в библиотеке).Вместо этого я бы порекомендовал библиотеку, в которой рассматриваемое состояние хранится в объектах.API библиотеки может быть C-подобным (экспортируемые функции, функции CreateXxxObject () / DestroyXxxObject (), которые возвращают указатели на непрозрачные struct s, подобные APR ), или C ++ - подобные.Придет время, когда модель-синглтон его не обрежет.

Однако я отвечаю только на заданный вопрос, а не говорю: «Сначала выброси свои планы, ...»

0 голосов
/ 29 июня 2011

Я недавно разработал очень похожий проект.В моем случае было доступно несколько архитектур, одна с использованием COM +, а другая с использованием p / Invoke.Я выбрал метод p / Invoke, потому что из-за простоты.У меня было много людей, которые прямо говорили мне, что это был неправильный подход, включая Microsoft!В конце концов, я смог использовать архитектуру p / Invoke без большой головной боли, но это было нелегко.Я был вынужден учесть различия между управляемыми и неуправляемыми структурами данных, передавая кучу в зависимости от стека, распределение памяти, проблемы перезаписи буфера / стека, проблемы безопасности ASP.Net и, прежде всего, архитектурные различия между управляемым и неуправляемым кодом.В конце концов, головная боль оставила меня намного лучшим программистом.

В ответ на вопрос о том, можно ли повторно управлять неуправляемой межъязыковой DLL из управляемого кода с использованием p / Invoke?Да, оно может.НО;он должен быть спроектирован таким образом, чтобы поддерживать его состояние реентерабельным образом.Это означает, что неуправляемая DLL должна отслеживать память, которую она выделяет, и освобождать эту память каждый раз, когда она вызывается из вашего веб-сервиса.Он не должен освобождать или выделять память, которая принадлежит другому вызову веб-службы.

0 голосов
/ 29 марта 2011

Я столкнулся с подобной проблемой несколько лет назад, работая с устаревшей неуправляемой DLL, которую нельзя было обновить. Проблема в том, что использование P / Invoke внутри веб-сервера не требует воспроизведения (я так и не понял, почему; мое лучшее предположение заключалось в том, что это была проблема безопасности). Мне нужно было обернуть вызовы DLL в службе Windows, а затем использовать вызов удаленного взаимодействия WCF для фальсификации взаимодействия. К сожалению, у меня больше нет доступа к этому коду, или я бы предложил вам лучший пример. Я надеюсь, что это может указать вам правильное направление.

0 голосов
/ 08 декабря 2010

Не понимаю, зачем вам загружать вещи через неуправляемые библиотеки.Если вы не знаете, что он делает и как он это делает, я понимаю, однако вы всегда должны сомневаться в том, что объекты внутри неуправляемых dll имеют деструкторы и правильное управление памятью.

Если вы знаете, что такое dllдостигает, и это не слишком много усилий, чтобы написать его в C #, вы можете использовать состояние сеанса ASP.NET для хранения данных между вызовами для каждого сеанса.

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

protected void Session_Start( object sender, EventArgs e ) 
{ 
  Trace.WriteLine( "Session_Start" ); 
}

В методе Session_Start файла global.asax вы можете добавить код, который выполняет медленный поиск данных и т. Д. (Эквивалент неуправляемой dll ...).Вы также можете сохранить эти данные либо в самом сеансе, либо создать статические переменные в global.asax, которые будут хранить данные (точно так же, как синглтон в неуправляемой dll) ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...