none
请教:关于COM组件中的辅助线程 RRS feed

  • 问题

  • // 某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``
    2010年6月17日 22:32

答案

  • 1 Single套间模型的COM组建,只在进程中第一个被创建的STA线程中实例化。其他线程需要通过代理发送消息到该线程的消息循环中,调用唯一实例。
    2 STA套间内COM对象的裸指针不能够直接传递给其他线程使用。需要进行列集处理。
    3 在STA线程中创建MTA套间模型的COM组建,或者在MTA线程中创建STA套间模型的COM组建,COM会从线程池中分配与组建类型相同的线程,用来运行组建。
    线程池中的STA线程具有消息循环,并要求指针调用强制序列化(保证裸指针被其他线程失败)。自定义的线程如不经特殊处理不具备强制序列化的功能。
    4 Both模型的COM组建,其套间模型与创建对象的线程模型一致。

    麻烦把正确答案设为解答。
    2010年7月6日 14:36
    版主

全部回复

  • 用CoMarshalInterThreadInterfaceInStream和CoGetInterfaceAndReleaseStream

    不要通过裸指针的形式传递COM接口。

    其实关于线程模型的问题。我本想发给你个例子,以前做的一个各种线程模型传递接口后的结果和原因。但上周特别忙,这周回家给你找一下。发给你。


    麻烦把正确答案设为解答。
    • 已标记为答案 Nancy Shao 2010年6月23日 6:19
    • 取消答案标记 MaRs`` 2010年6月24日 9:20
    2010年6月21日 1:38
    版主
  • 谢谢,但是通过接口无法访问到m_nValue怎么办?

    我也不想通过接口把m_nValue暴露给组件的客户。


    MaRs``
    2010年6月21日 1:44
  • 对于 COM线程模型,由于IA_Func是接口,而上述功能都是该接口中的实现。所以线程模型对实现没有影响的。你这个实现没有问题。对于各种线程模型,是客户端是否可以正确调用IA_FUnc

    麻烦把正确答案设为解答。
    2010年6月22日 1:59
    版主
  • 还是不太明白。

    如果threadProc中调用到其他接口(非CA类实现的接口),那这个实现还是正确的吗?


    MaRs``
    2010年6月24日 4:18
  • // 某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对上述问题的答案有影响吗?
    

    如果threadProc中会调用到CA聚合或包容的其他接口,答案又是如何呢?
    MaRs``
    2010年6月27日 1:26
  • // 某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对上述问题的答案有影响吗?
    
    

    如果threadProc中会调用到CA聚合或包容的其他接口,答案又是如何呢?

    MaRs``
    2010年7月4日 16:19
  • 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对象


    麻烦把正确答案设为解答。
    2010年7月6日 14:35
    版主
  • 创建

    分别在两个线程中使用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对象的线程不同  


    麻烦把正确答案设为解答。
    2010年7月6日 14:35
    版主
  • 1 Single套间模型的COM组建,只在进程中第一个被创建的STA线程中实例化。其他线程需要通过代理发送消息到该线程的消息循环中,调用唯一实例。
    2 STA套间内COM对象的裸指针不能够直接传递给其他线程使用。需要进行列集处理。
    3 在STA线程中创建MTA套间模型的COM组建,或者在MTA线程中创建STA套间模型的COM组建,COM会从线程池中分配与组建类型相同的线程,用来运行组建。
    线程池中的STA线程具有消息循环,并要求指针调用强制序列化(保证裸指针被其他线程失败)。自定义的线程如不经特殊处理不具备强制序列化的功能。
    4 Both模型的COM组建,其套间模型与创建对象的线程模型一致。

    麻烦把正确答案设为解答。
    2010年7月6日 14:36
    版主