Использование unmanaged dll из C#, часть 4

ChaiTestWork0
(продолжение статьи)
Как показало дальнейшее. Имеется трудноразрешимая проблема. Если в старых программах на С++ все работало на ура, то при использовании из .NET вылезают проблемы. Когда мы получаем и отправляем редкие, одиночные пакеты — все хорошо, но стоит появиться большому потоку данных, то про вызове нашего делегата, в конце концов происходит нарушение защиты. Я пробовал перевести все используемые функции и переменные в static, чтобы их не трогал сборщик мусора. Становилось лучше, но через несколько минут работы все равно происходило нарушение защиты. Так как у меня старый и уже не поддерживаемый прибор, я связался с предыдущим местом работы (там у нас был еще один PCI вариант, который до сих пор поддерживается производителем. Перекомпилил все с использованием последней версии библиотеки. И все равно проблема осталась. Почитав документацию к последней версии, я увидел, что они не рекомендуют больше использовать callback функции. А рекомендуют использовать CiWaitEvent (который под виндами использует WaitForSingleObject).

Видимо, как я думаю, тоже столкнулись с этой проблемой и уперлись в какую-то неразрешимую заковыку. (ну это мои домыслы). В исходниках консольной canmon что идет с библиотекой, так же уже все поменяно с каллбаков на _beginthreadex и собственный поток обработчик использующий CiWaitEvent. В общем, упразднил я таковые из импорта и сделал свои обработчики (код слегка урезан, чтоб не загромождать текст и без того большими кусками кода):

Ну и вот так, это использовать (исключительно тестировал, не падает ли при большом количестве входящих сообщений):

Без Chai.Dispose() по закрытии программы, поток обработчика не прекращается. Так что не надо забывать освобождать этот поток, когда обработчик больше не нужен.
Кроме того, часть функций, статическая. А статические функции не имеют доступа к динамическим полям формы. Так как в нашем случае форма одна единственная, и других экземпляров этого класса не предвидится, мы можем сделать не совсем корректную вещь, и получать к ним доступ обращаясь к экземпляру класса по имени. Что и делает функция staticThis().

В button1_Click() мы инициализируем класс интерфейс библиотеки. При этом сканируется обороудование и заполняется два списка borаds и channels. Первый исключительно информационный, и нужен больше для интерфейса. Второй же это список доступных каналов, на всем подключенном CHAI-совместимом оборудовании. (а вдруг мы несколько устройств подключили, а ди на одном интерфейсе может быть несколько каналов).
У каждого канала есть свой собственный набор обработчиков .OnRcv(), .OnTrmt() , .OnErr() которым может быть присвоена пользовательская функция. Метод .Open() канала открывает канал и создает поток обрабочика сообщений. А метод .Start(); запускает канал и так же запускает поток обработчика сообщений.

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *