如何跨线程触发COM事件

COM通过连接点来实现类似C里的回调函数的功能,实现了Observe设计模式,从而可以对模块进行很好的解耦。特别是在VS.NET里,微软通过Attribute来极大的简化的COM的开发以及COM连接点的实现。在《 初识统一事件模型之COM连接点》一文里,我对此进行了简要的描述。

使用COM连接点的好处就是,在Managed Code里引用COM组件的时候,连接点自动转换成了委托(Delegate)对象,再加上VS.NET的自动代码完成,简直是太轻松了。你只要试过使用ATL和MFC来实现连接点,就会知道有多麻烦了。

好了,就在我以为事情已经很简单的时候,突然遇到了一个棘手的问题。那就是,如果在工作线程里触发事件的话,虽然在Unmanaged的C++代码里可以接收,但却无法在Managed Code里接收到该事件。我知道自己遇到了COM里最复杂的线程模型(Threading Model)了,一直就没有认真搞明白过......

然后找到这篇文章 《PRB: Firing Event in Second Thread Causes IPF or GPF》,虽然说的是VB,但是问题是一样的。基本的原因就是,跨线程的调用需要列集--又是一个复杂的技术。解决办法有两个,其中之一就是在工作线程里发送消息给主线程,再从主线程里发出事件。又是消息,最反感的就是用Windows来递送消息,常常会跟界面耦合得很厉害。但是,在Windows的世界里,用消息传递数据和控制又是最最常见的。为了避免跟界面耦合,常常会创建不可见的窗口,只为了用其消息队列。OK,这个方法倒也简单,虽然不够完美。

问题解决了,现在想来用消息来传递是否也是一种比较好的耦合方式呢?因为相比之下,函数调用的耦合方式要比消息传递要紧密得多。消息的扩展可以很简单和随意,但是函数的增加就很严格,特别是在静态链接的语言里。Windows得以发展那么多版本,其扩展性不得不归功使用松散的消息耦合。换成接口,不知道要派生多少个版本了呢。所以,接的在《.NET设计规范》里,作者推荐使用abstract class而不是interface,因为前者增加函数不会影响以前的代码。又想起来,曾经看过一期Channel 9的采访,讲的是MS Research正在用C#写一个OS,一个模块就是一个进程,并且进程之间完全用消息来传递,也不允许Dll注入(以保证运行稳健)。在这样的模型里,消息显得更加灵活和具有扩展性。在OOP里,对象之间的交互,消息和方法调用表示本来就很模糊。据说Smalltalk的对象之间就是用消息来传递的。另外,在动态语言如Ruby里,其实函数调用和消息的界限就更模糊了,反正都是动态去查询,跟消息分发的效果是一样的.......

你可能感兴趣的:(设计模式,windows,扩展,smalltalk,interface,firing)