积极答复者
请教:关于COM组件中的辅助线程

问题
-
// 某COM组件CA实现了IA接口。IA接口有一个函数IA_Func1,CA的实现如下: class CA { //... void CA_Method1(); private: long m_nValue; }; HRESULT CA::IA_Func1() { CreateThread(NULL,0,threadProc,this,0,NULL); return S_OK; } unsigned long CA::threadProc(LPVOID param) { CA *pCA = (CA*)param; //这个转换不确定是否能成功(STA、MTA、DCOM远程组件) pCA->CA_Method1(); //由于上面的不确定,这里也不确定是否能成功调用 InterlockedIncreament(&pCA->m_nValue); //同上 return 0; }
// threadProc只会调用CA类实现的函数或API函数,不会调用到其他接口;
// 这样能在各种客户端套间环境(STA/MTA/BOTH/None)下正确运行吗? // CA的ThreadingModal对上述问题的答案有影响吗? // 困扰很久了,一直无法确定答案。 // 如果不行的话:由于IA_Func1是个很耗时的操作,所以必须开启工作线程。 // 在工作线程中如何才能安全的访问到CA类的辅助函数及类变量呢?
MaRs``
答案
-
1 Single套间模型的COM组建,只在进程中第一个被创建的STA线程中实例化。其他线程需要通过代理发送消息到该线程的消息循环中,调用唯一实例。 2 STA套间内COM对象的裸指针不能够直接传递给其他线程使用。需要进行列集处理。 3 在STA线程中创建MTA套间模型的COM组建,或者在MTA线程中创建STA套间模型的COM组建,COM会从线程池中分配与组建类型相同的线程,用来运行组建。
线程池中的STA线程具有消息循环,并要求指针调用强制序列化(保证裸指针被其他线程失败)。自定义的线程如不经特殊处理不具备强制序列化的功能。4 Both模型的COM组建,其套间模型与创建对象的线程模型一致。
麻烦把正确答案设为解答。- 已标记为答案 VongerModerator 2011年3月4日 14:00
全部回复
-
// 某COM组件CA实现了IA接口。IA接口有一个函数IA_Func1,CA的实现如下: class CA { //... void CA_Method1(); private: long m_nValue; }; HRESULT CA::IA_Func1() { CreateThread(NULL,0,threadProc,this,0,NULL); return S_OK; } unsigned long CA::threadProc(LPVOID param) { CA *pCA = (CA*)param; //这个转换不确定是否能成功(STA、MTA、DCOM远程组件) pCA->CA_Method1(); //由于上面的不确定,这里也不确定是否能成功调用 InterlockedIncreament(&pCA->m_nValue); //同上 return 0; } // threadProc只会调用CA类实现的函数或API函数,不会调用到其他接口; // 这样能在各种客户端套间环境(STA/MTA/BOTH/None)下正确运行吗? // CA的ThreadingModal对上述问题的答案有影响吗?
MaRs`` -
// 某COM组件CA实现了IA接口。IA接口有一个函数IA_Func1,CA的实现如下: class CA { //... void CA_Method1(); private: long m_nValue; }; HRESULT CA::IA_Func1() { CreateThread(NULL,0,threadProc,this,0,NULL); return S_OK; } unsigned long CA::threadProc(LPVOID param) { CA *pCA = (CA*)param; //这个转换不确定是否能成功(STA、MTA、DCOM远程组件) pCA->CA_Method1(); //由于上面的不确定,这里也不确定是否能成功调用 InterlockedIncreament(&pCA->m_nValue); //同上 return 0; } // threadProc只会调用CA类实现的函数或API函数,不会调用到其他接口; // 这样能在各种客户端套间环境(STA/MTA/BOTH/None)下正确运行吗? // CA的ThreadingModal对上述问题的答案有影响吗?
MaRs`` -
sorry,上周比较忙
我以前总结的:
1 传递
分别在两个线程中使用COM、传递COM指针。 主线程:第一个创建COM对象的线程。调用COM接口,负责创建辅助线程,并且列集COM对象指针,并且把裸指针或者列集指针传递给辅助线程。 辅助线程:在辅助线程中创建创建COM对象,或者通过主线程传递的裸指针或者列集指针调用COM接口。 调用方式:
列集传递,通过CoMarshalInterThreadInterfaceInStream和CoGetInterfaceAndReleaseStream列集传递COM指针
传递指针,传递裸指针结果:运行COM对象的线程是否一样。调用失败,或者死等 COM对象套间模型 主线程
套间模型辅助线程
套间模型调用方式 在主线程中是否存在消息循环 结果 原因 Single STA STA/MTA 列集传递 否 主线程调用成功,
辅助线程创建操作死等Single只在第一个创建的STA线程中实例化一次。其他线程访问,需要在创建Single对象的线程创建消息循环 Single STA STA/MTA 列集传递 是 运行COM对象的线程相同 Single/Apartment STA STA/MTA 传递指针 -- 运行COM对象的线程不同 http://support.microsoft.com/kb/q206076/
COM默认线程带有强制检查,而自己的STA,MTA线程没有这样的检查。
错误用法错误用法,无法保证线程安全Single MTA STA/MTA 传递指针 -- 主线程调用成功,辅助线程调用失败 http://support.microsoft.com/kb/q206076/
COM默认线程带有强制检查,而自己的STA没有这样的检查。
Single MTA STA/MTA 列集传递 -- 运行COM对象的线程相同 COM线程池中线程,使用Single对象。COM线程池中线程支持消息循环 Apartment MTA STA 传递指针 -- 主线程调用成功,辅助线程调用失败 http://support.microsoft.com/kb/q206076/
COM默认线程带有强制检查,而自己的STA,MTA线程没有这样的检查。
错误用法
Apartment MTA MTA 传递指针 -- 运行COM对象的线程相同 COM线程池中线程带有强制检查,而自己的STA,MTA线程没有这样的检查。
错误用法,无法保证线程安全Apartment STA STA/MTA 列集传递 否 主线程调用成功,
辅助线程创建操作死等Apartment STA STA/MTA 列集传递 是 运行COM对象的线程相同 Apartment MTA STA/MTA 列集传递 -- 运行COM对象的线程相同 Free MTA STA/MTA 列集传递 -- 运行COM对象的线程不同 Free STA STA 列集传递 -- 运行COM对象的线程相同 Free STA MTA 列集传递 -- 运行COM对象的线程不同 Free MTA STA/MTA 传递指针 -- 运行COM对象的线程不同 Free STA MTA 传递指针 -- 主线程调用成功,辅助线程调用失败 http://support.microsoft.com/kb/q206076/
Free STA STA 传递指针 -- 主线程调用成功,辅助线程调用失败 http://support.microsoft.com/kb/q206076/
Both STA STA/MTA 传递指针 -- 运行COM对象的线程不同 COM线程池中线程带有强制检查,而自己的STA,MTA线程没有这样的检查。
错误用法,无法保证线程安全Both MTA STA/MTA 传递指针 -- 运行COM对象的线程不同 COM线程池中线程带有强制检查,而自己的STA,MTA线程没有这样的检查。
由服务器端保证线程安全Both MTA STA 列集传递 -- 运行COM对象的线程不同 COM线程池中线程带有强制检查,而自己的STA,MTA线程没有这样的检查。 Both STA STA/MTA 列集传递 否 主线程调用成功,
辅助线程创建操作死等创建Apartment对象 Both STA STA/MTA 列集传递 是 运行COM对象的线程相同 Both MTA STA/MTA 列集传递 -- 运行COM对象的线程不同 创建Free对象
麻烦把正确答案设为解答。 -
创建
分别在两个线程中使用COM、传递COM指针。 主线程:第一个创建COM对象的线程。调用COM接口,负责创建辅助线程,并且列集COM对象指针,并且把裸指针或者列集指针传递给辅助线程。 辅助线程:在辅助线程中创建创建COM对象,或者通过主线程传递的裸指针或者列集指针调用COM接口。 调用方式:创建,通过CoCreateInstance创建COM对象 结果:主线程和辅助线程调用的COM对象是否为同一个实例。运行COM对象的线程是否一样。 COM对象套间模型 主线程
套间模型辅助线程
套间模型调用方式 在主线程中是否存在消息循环 结果 原因 Single STA STA/MTA 创建 否 主线程调用成功,
辅助线程创建操作死等Single只在第一个创建的STA线程中实例化一次。其他线程访问,需要在创建Single对象的线程创建消息循环 Single STA STA/MTA 创建 是 两线程调用同一个COM对象,运行COM对象的线程相同 Single MTA STA/MTA 创建 -- 两线程调用不同COM对象,运行COM对象的线程相同 在MTA线程中创建Single对象,Single存在于COM的默认线程。进程并没有创建一个STA线程。 Apartment MTA MTA 创建 -- 两线程调用不同COM对象,运行COM对象的线程相同 COM默认线程中创建两个不同对象 Apartment MTA/STA STA 创建 -- 两线程调用不同COM对象,运行COM对象的线程不同 Free STA STA 创建 -- 两线程调用不同COM对象,运行COM对象的线程是否相同不能确定 COM默认MTA线程中创建两个对象,MTA可能不为同一个线程 Free STA MTA 创建 -- 两线程调用不同COM对象,运行COM对象的线程不同 Free MTA STA/MTA 创建 -- 两线程调用不同COM对象,运行COM对象的线程不同 Both STA/MTA STA/MTA 创建 -- 两线程调用不同COM对象,运行COM对象的线程不同
麻烦把正确答案设为解答。 -
1 Single套间模型的COM组建,只在进程中第一个被创建的STA线程中实例化。其他线程需要通过代理发送消息到该线程的消息循环中,调用唯一实例。 2 STA套间内COM对象的裸指针不能够直接传递给其他线程使用。需要进行列集处理。 3 在STA线程中创建MTA套间模型的COM组建,或者在MTA线程中创建STA套间模型的COM组建,COM会从线程池中分配与组建类型相同的线程,用来运行组建。
线程池中的STA线程具有消息循环,并要求指针调用强制序列化(保证裸指针被其他线程失败)。自定义的线程如不经特殊处理不具备强制序列化的功能。4 Both模型的COM组建,其套间模型与创建对象的线程模型一致。
麻烦把正确答案设为解答。- 已标记为答案 VongerModerator 2011年3月4日 14:00