现在在做一个addin的项目。本来只是一个比较简单的玩意,一个新feature的需求使得我有机会搞了一点interprocess的code。虽然coding的复杂度并不大,不过的确加深了关于interprocess sync的理解。note it down。

需求:这个addin涉及的application包括两个。原来的行为是:每一次从一个app(app1)通过addin调用另一个application(app2)来完成一部分工作时,都是启动一个新的进程instance,用户抱怨启动速度太慢,并且希望可以reuse已经打开了的app2。但是,在app2中的工作完成之前(return to app1 button click),app1必须是被freeze状态。

分析及实现:

主要涉及两个关键点:

1)如何reuse已经打开的app2。solution:已经有了LaunchApp.exe这个程序专门干这个事。

2)如何在用户完成在app2的工作之前,lock住app1。solution:这就用到了进程间通讯的设施。简单讲就是一类叫做signal信号量的类,包括了Mutex,event,critical section等。他们其实就是可以跨进程或线程访问的一些全局数据或访问点。对于我的需求而言,要做的其实就是:在app1的addin里,创建出一个跨进程的signal对象(比如event或Mutex),然后使得它一直等待;在app2中,通过使用那个跨进程的signal对象发信号给app1,来告知他这边工作的完成,从而可以让app1恢复工作。研究下来,适合用的只有manual reset event,因为只有他是可以设置处于signal或不处于signal状态的。做法:在app1的addin里,createevent并且初始化为notsignal状态,然后让addin进入等待event变成signal状态的循环;在app2中,openevent来获取app1里创建的event handle,setevent来改变event变为signal状态。这样的话,app1里的waitforsingleobject就能获取到event的访问权了(其前提是event是signal状态),从而可以继续往下执行,unlocked。

小结一下:

1. .net remoting.记下一点:当launcher connect到app2里的remote object时,实际上是在app2进程里新开了一个线程来执行。我碰到的问题是:当我在那个新开的线程里试图改变app2的UI时,抛出异常并告诉我:"another thread owns the object"。另一个线程指的就是main thread主线程。所以,在那个新开的线程里做的事情很有限。要想做比如打开文档,改变UI之类的事情,需要用到postmessage来最终在主线程里做事情。

2. interprocess sync。 本质上,那些所谓的信号量对象可以认为是OS级的全局变量,因此可以被进程们访问。记下一点:donet提供了system.threading及下面的类,而native c++有一组sync functions,这篇文章对各种signal方式进行了比较:synchronization objects for interprocess synchronization and multi-threadiing。基于我目前的理解,除了manual reset event,其他的signal对象默认都是出于signal状态,因此任何在监听它的线程或进程都可以获取其使用权(一旦它处于闲置状态),适用于对线程或进程的执行顺序没有要求的场合;而manual reset event,可以出于非signal状态,这一点可以被利用来精准控制线程或进程在某一段时间的执行顺序。比如我碰到的问题就有这样的要求。