Предотвращение событий C # в коде VB6 для создания мертвой блокировки - PullRequest
4 голосов
/ 04 ноября 2011

Я создал многопоточную COM-сборку C #, я использовал ее из VB6.

C # -COM может вызывать события из нескольких потоков, я создал невидимый объект From и использовал его для синхронизации всех событий доподнять их.

if (myForm.InvokeRequired() )
{
  delOnMessage myDelegate = new delOnMessage(Message_received);
  myForm.Invoke(myDelegate, new object[] { null, null });
}
else
{
  RaiseMyEvent();
}

Но если VB6-код находится внутри обработчика события и вызывает некоторые методы COM-объекта, это может привести к новому событию.

Private Sub m_SomeClass_SomeEvent(obj As Variant)
    COMobject.SendAnAnswer() ' This produces a new event
End Sub

В этом случае часть системы событий перестает работать, удивительно, что Main VB6 Applikation все еще работает.

РЕДАКТИРОВАТЬ: более подробно
Если C # -COM получил сообщение (от CAN-Bus-Thread), он создает событие, в некоторых случаях VB6 вызывает C # -COMметод, который создает событие, это событие также достигается VB6.
Но тогда кажется, что поток CAN-Bus заблокирован, так как больше сообщений не принимается (до перезапуска программы).
Но могут возникать другие события,

CAN-Bus-Thread представляет собой бесконечный цикл для получения сообщения и запуска события.

У меня два вопроса:

Мой способ синхронизацииправильно?
Возможно ли без изменения VB6-кода заставить его работать?

Ответы [ 2 ]

2 голосов
/ 04 ноября 2011

Я создал невидимый объект From

Звучит как проблема.Использование InvokeRequired является опасным анти-паттерном.Это особенно смертоносно с VB6, во время его выполнения плохо работает обработка потоков.Вы знаете , что код вызывается из рабочего потока, используйте InvokeRequired только для проверки того, что форма, которую вы используете для синхронизации, находится в надлежащем состоянии, чтобы сделать это правильно:

if (!myForm.InvokeRequired()) {
    throw new InvalidOperationException("Synchronization window not created");
}
delOnMessage myDelegate = new delOnMessage(FireMessageReceivedEvent);
myForm.BeginInvoke(myDelegate, new object[] { null, null });

Хорошие шансы, что это исключение вызовет, создать невидимую форму не так просто.Вы можете принудительно создать свойство Handle формы, прочитав его свойство Handle.Или переопределив его метод SetVisibleCore (), чтобы сохранить форму невидимой:

    protected override void SetVisibleCore(bool value) {
        if (!this.IsHandleCreated) {
            this.CreateHandle();
            value = false;
        }
        base.SetVisibleCore(value);
    }

Однако очень важно, чтобы вы вызывали метод Show () этой формы в главном потоке.Это все равно не будет работать правильно, если вы создадите форму в своем рабочем потоке.Нет простого способа проверить это в вашем коде.Используйте отладчик и окно Debug + Windows + Threads, чтобы убедиться в этом.

И последнее, но не менее важное: предпочитайте BeginInvoke () вместо Invoke ().Это имеет гораздо меньшие шансы создания тупика.Это может вызвать проблемы само по себе, однако, ваш рабочий поток может нуждаться в регулировании, чтобы предотвратить его заполнение основного потока запросами на вызов.

2 голосов
/ 04 ноября 2011

В зависимости от характера события может быть достаточно просто переключиться с Invoke на BeginInvoke, чтобы оно было выгружено в очередь сообщений (без блокировки, поэтому без блокировки). Удобно, что Control.BeginInvoke (в отличие от Delegate.BeginInvoke) не требует, чтобы вы звонили EndInvoke, поэтому вы можете использовать это как "забыл и забыл".

Я может испытать искушение исключить какую-то дополнительную работу, однако:

myForm.BeginInvoke((MethodInvoker)RaiseMyEvent);

(т. Е. Прямой переход к RaiseMyEvent)

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