COM对象引用计数是thread safe的么?
STDMETHOD_(ULONG, Release) (void)
{
ulRefs = InterlockedDecrement(&m_ulRefs);
if(ulRefs==0)
{
delete this;
}
return ulRefs;
}
假设m_ulRefs=1,当InterlockedDecrement调用完毕之后,m_ulRefs=0,如果在if语句之前发生线程调度,另外一个线程调用AddRef改变了m_ulRefs,那么ulRefs将成为脏数据,调用delete就是不应该的,这样能确保com对象线程安全吗?是否需要使用临界区来保护整个函数?
[解决办法]
存在这种情况吗?在引用计数的最后一次可能的release意味着该COM对象要被使用者释放,而其他线程中他又被使用,这属于使用者的不正确使用,不挨着组件实现者吧。
[解决办法]
就像1楼说的,那是使用者的错误
例如:
Intf1.Release();//应该认为Intf1是无效接口了
Intf2.Release();//应该认为Intf2是无效接口了
//假设这而接口都释放了,所以m_ulRefs已经是0了
//如果你再调用Intf1.AddRef(),实际上就是使用者用错了。
[解决办法]
不正确的使用计数器可能会出现你说的情况。
这里只是可能出现,并不一定出现。为什么呢
这得看组件是否是STA类型的,如果是STA类型是不会
但如果是MTA类型如果是不正确的使用计数器,
如果是增加了,但是忘了在使用完了后释放,这样情况组件将永远不会被卸载,
你说的那种情况是不会出现问题的。
但是是如果是使用不增加反而是减少,那么会出现你说的情况并且程序会崩溃!
你的问题含盖了两个方面的问题:
1.计数器正确使用的原则
2.组件的线程安全问题
其实避免忘了AddRef和Release的调用还有中方法
那就是智能指针
[解决办法]
STA类型也用不着InterlockedDecrement,有人说的好“不存在的问题是无法解决的”
[解决办法]
引用计数只是考虑了组件的生命期,它与线程同步,线程安全没有太大关系。线程同步主要考虑线程互斥,事件信号问题。
STA也就是套间线程,MTA也就是自由线程。
一般而言,在使用套间线程的情况下,所有的调整和同步处理将由COM完成。而在自由线程的情况下,调整处理可能是不需要的,而同步则需要组件自己完成
下面是一些需要记住的一般性规则:
进程间的调用将被调整
同一线程中的调用被不被调理
同一线程中的调用将由此线程本身完成同步。
对于套间线程中组件的调用将被调整
对于套间线程的调用将被同步
对于自由线程中组件的调用并不是总被调整。
对于自由线程的调用将不被同步
以下各种线程组合均在同一进程中实现
1.同一线程中的调用:
调用将被自然地同步,COM不需要作任何同步工作,而组件也不需要是线程安全的。调用也不需要被调整。
2.套间线程对套间线程的调用。
COM将此调用进行同步。COM也将对接口进行调整。在某些情况下,需要程序员自己完成对套间线程间接口的调整。对套间线程中组件的调用与进程外组件的调用是相似的。
3.自由线程对自由线程的调用。
COM不会对此调用进行同步,调用不被调整。此调用将在客房线程中执行。程序员本身需要同步线程对组件的访问。
4.自由线程对套间线程的调用
COM将对此调用进行同步。此组件将在套间线程中被调用。在大多数情况下,此种调整将由COM完成,但在某此情况下,需要程序员完成这种调整。
5.套间线程对自由线程的调用。
COM不会对此调用进行同步,同步工作由组件完成。接口将被进行调整,此时COM会对调整进行优化,以将指针直接传给客户。
同步处理是一个一般性的多线程编程问题,而参数调整则是COM所特有的从多个线程中处理COM组件的独特领域。
COM需要知道进程中组件支持的线程模型以便能在跨越线程边界对其接口进行合适的调整与同步。
HKEY_CLASS_ROOT\CLSID\{xxxxxxxx-XXXX-XXXX-XXXXXXXXXXXX}\InprocServer32项下添加ThreadingModel键,它的值可以是:
1.Apartment 组件支持套间线程。
2.Free 组件支持自由线程
3.Both 组件支持两种线程模型。