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里面所讲的。
假设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里面所讲的。