Q: "为什么如果我们把这两个组件安装在同一个COM+组件包中问题就不会出现"(zz)

A: 问题的根源在于COM+ 如何assign一个worker thread 来用于clients 的CreateObject 请求。在COM+ 1.0 (Win2000)下,如果机器是单CPU, STA thread pool 的起始大小为 8, 上限为10。通常情况下每个STA worker thread 会接受5个CreateObject 请求,然后COM+ runtime才决定create新的STA worker thread. 这样达到的效果是: 两个或多个objects会共享同一个STA worker thread.
假设obj1 和obj2 共享 一个STA worker thread. 如果obj1正在呼出自己的aparment (比如调用另外一个进程里的objects等等), 恰好这时clients请求obj2的方法调用,根据STA apartment的可重入性(reentrancy), obj2会允许获得在该STA worker thread 上执行的权利。而obj1在完成自己的呼出后必须重新要求获得对该STA worker thread的控制权。一种极端的情况时,如果obj2执行的操作很长时间不返回,那么obj1必须等待。

回到原来的例子中,假设obj1和obj2都属于component A, 然后b属于component B,obj1创建了b. 当A 和B都在同一Server package中时候,obj1和b 属于同一apartment (进一步属于同一com+ context), 这样在obj1 呼叫b的时候,并没有呼出apartment, 所以调用都是同步的 (换句话说,此时即使有clients调用obj2的请求也必须等待obj1完成后方可)。与之相对比的是如果AB配在不同的server package中,那么obj1呼叫b时候则允许obj2也允许在该STA worker thread 上同时执行 (在本例子中调用后台的SQL2K)。换句话讲DCOM 在处理STA呼出时候是区分该呼出是在同一还是非同一apartment中的。obj1在完成呼叫b后需要重新获得对其STA worker thread 的控制权才能要求DTC提交transaction。这样的话obj1要等待obj2完成对数据库的调用(obj2通常是在update/insert tables), 而obj2要等待obj1提交transaction从而释放占有的locks。 Deadlock!!

从上面的分析我们可以看到,最有效的方法是不使用STA thread pool而使用MTA thread pool (就是把component封装到MTA 中)。 MTA thread 的好处是objects跟thread 没有绑定关系,obj1执行完后不比等待重新进入创建他的thread;另外MTA worker thread的大小没有上限。

作为一个workaround,我们可以要求STA worker thread开始时候每个object都获得一个单独的worker thread, 从而最大限度减少因为两个objects共享worker thread引起的deadlock, 这就是Q303071里面所讲的。

posted on 2004-05-21 01:34  Snowwolf  阅读(897)  评论(0编辑  收藏  举报

导航