关于多线程使用com的问题

robert_wjj 2008-10-06 10:39:51
对com不熟悉,但是用到了一个jmail的com组件。我的程序是多线程的,出了点问题,有些时候程序会随机崩溃,估计是线程并发冲突。
google查了下,好像有人说STA的com不能多线程,我也不大懂。不知道这个jmail是STA的么,怎么看?
那我就把CoInitialize(NULL)和CoUninitialize()放到进程中,在所有线程开始前初始化,所有线程结束后释放。
但是这样程序出异常:_com_error,根本没办法发邮件了。
...全文
447 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
gzstyxb 2008-10-25
  • 打赏
  • 举报
回复
多线程使用COM?在COM中使用多线程?
Amuro1987218 2008-10-25
  • 打赏
  • 举报
回复
我去年用过jmail,也是多现成环境,可能同时会发N个邮件,没出现这种情况。
nodiebirdcomeback 2008-10-24
  • 打赏
  • 举报
回复
组件必须是支持MTA的情况下使用CoInitializeEx才可以创建组件的自由套间
在STA模式下多线程对于在接口的函数调用必须通过封送才可以正常使用
但是对于接口的函数的调用只能在创建组件的线程里完成,在STA模式下
的接口函数的执行是按调用的顺序执行的。
在某一线程ThreadA中,其部分代码如下
IStream* pIStream = NULL;

{
CoInitialize(NULL);
Unknown *I;
IYourInterface* IY;

CoCreateInstance(,,,,&I);
I->QueryInterface(...,&IY);
CoMarshalInterThreadInterfaceInStream(IID_IY,pIY,&pIStream);
.............

CoUninitialize();
}

另外一个线程ThreadB使用ThreadA创建的组件的方法如下:
{
IYourInterface* IY1;
CoGetInterfaceAndReleaseStream(pIStream,IID_IY,(void**)&pIY1);
}
查看组件支持的线程模型在注册表可以看到
在CLID目录下的子目录下的ThreadingModel的项目有指定
如果没有ThreadingModel的一律为STA模式
Jackword 2008-10-24
  • 打赏
  • 举报
回复
你把catch到的_com_error print出来看看
E.Description();
hbuzzd 2008-10-20
  • 打赏
  • 举报
回复
我试了一下,貌似在线程之前调用CoInitializeEx也可以啊!你试试吧!
hbuzzd 2008-10-20
  • 打赏
  • 举报
回复
多线程模式下是必须用CoInitializeEx来初始化COM库的。
至于组件不支持多线程可能是线程模式的问题吧!
nodiebirdcomeback 2008-10-08
  • 打赏
  • 举报
回复
不同的STA进行接口指针的传递要调用COM库函数封送才行的!
robert_wjj 2008-10-07
  • 打赏
  • 举报
回复
之前搞错了,在线程内部创建各自的jmail实例对象是可以的不会崩溃,崩溃是因为另一个原因已解决。
但是这样做的话速度好慢啊。
如果在进程中一次性CoInitialize(NULL)和CoUninitialize(),速度快了好多倍,但是可惜是不稳定,发了几百封邮件就会崩溃。
为什么这个组件不能支持多线程呢?有没有好的办法?
robert_wjj 2008-10-06
  • 打赏
  • 举报
回复
刚才又在进程里,把CoInitialize(NULL); 换成了CoInitializeEx(NULL , COINIT_MULTITHREADED);
奇怪没有对应的CoUninitializeEx(NULL, COINIT_MULTITHREADED);看了别人的例子是CoInitializeEx和CoUninitialize配对的。
这时候邮件发送成功了,不报_com_error异常。但还是中途会随机崩溃。。。。。
robert_wjj 2008-10-06
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 vieri_ch 的回复:]
CoInitialize(NULL)和CoUninitialize() 的作用域是基于线程的,所以必须每个线程都作COM初始化。
你可以在线程内部创建各自的jmail实例对象试试看
[/Quote]

刚开始就是每个线程中都这么做:

try
{
CoInitialize(NULL);
sendMailToManagers(managers, alarmMessage);
CoUninitialize();
} catch( _com_error & E) {
ACE_ERROR ((LM_ERROR, ACE_TEXT("%D %N %l:发送报警邮件给管理员出错, _com_error\n")));
} catch(...) {
ACE_ERROR ((LM_ERROR, ACE_TEXT("%D %N %l:发送报警邮件给管理员出错,其他错误\n")));
}
但是会在中间随机崩溃,估计是不能多线程用这个jmail组件。
aqiu348503 2008-10-06
  • 打赏
  • 举报
回复
是否STA可从注册表里看,多线程要用CoInitialize(NULL,COINIT_MULTITHREAD)初始化
尘雨 2008-10-06
  • 打赏
  • 举报
回复
CoInitialize(NULL)和CoUninitialize() 的作用域是基于线程的,所以必须每个线程都作COM初始化。
你可以在线程内部创建各自的jmail实例对象试试看

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧