防止C#事件到VB6代码创建死锁

我创建了一个多线程C#COM-Assembly,我在VB6中使用它.

C#-COM可以从多个线程激发事件,我创建了一个不可见的From-object,并在引发之前使用它来同步所有事件.

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

但是,如果VB6-Code位于事件处理程序内并调用COM-Object的某些方法,则会产生新事件.

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

在这种情况下,事件系统的一部分停止工作,令人惊讶的是主VB6 Applikation仍然有效.

编辑:更详细
如果C#-COM收到一条消息(来自CAN-Bus-Thread),它会创建一个事件,在某些情况下,VB6会调用一个C#-COM方法来创建一个事件,这个事件也会到达VB6.
但随后CAN-Bus-Thread似乎被阻止了,因为没有收到更多的消息(直到程序重启).
但其他事件可能会发生.

CAN-Bus-Thread是一个无限循环,用于接收消息并触发事件.

我有两个问题:

我的同步方式是否正确?
是否可以在不修改VB6代码的情况下使其正常工作?

解决方法:

I created an invisible From-object

这听起来像麻烦.使用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()方法非常重要.如果在工作线程中创建表单,它仍然无法正常工作.在代码中检查这一点并不容易.使用调试器和“调试Windows线程”窗口来验证这一点.

最后但同样重要的是,请支持BeginInvoke()而不是Invoke().这造成死锁的几率要小得多.这可能会导致问题,但是,您的工作线程可能需要受到限制,以防止它通过调用请求充斥主线程.

上一篇:【Python】连接到Oracle数据库的前奏:安装cx_Oracle


下一篇:如何将python代码生成exe小程序