今天发现了一个问题,或者说这个问题以前发生过,今天又发生了,就是重入导致的crash。
大致流程说明如下.
环境说明
1. GUI线程(进程中只有一个,且是主线程).
2. 存在一个chatdlg 是个对话框,这个对话框聚合了一个 mainslot(实际上是一个工具条),这是一个com对象,STA对象。
3. mainslot 派生自一个公共父类slotbase .
4. slotbase 又聚合了多个iteminfo(工具条按钮),也是com对象,不过注意这个com对象是free模型的。
运行流程说明
1. chatdlg 开始销毁(OnDestroy)。
2. mainslot 开始析构.
3. slotbase 开始析构。
4. iteminfo开始析构. 这儿来了,由于iteminfo是free模式的com,因此slotbase在主线程中由com库发起了一个sendwait,然后启动了一个消息循环,防止主线程僵死。
5. 还没有彻底销毁的chatdlg 在sendwait还没有返回前,也就是说com库还没有撤销messageloop的时候,收到了一个WM_XXX, 而这个wm_xxx .
6. OnWMXXX 得到了执行。
7。这儿注意了, 实际上ondestroy还没有完成,但是gui线程又被重入了,当然程序可能没有问题,不过不幸的是,这次是有问题的。
总结来说,运用com线程的时候,特别以后跨越进程边界时候越来越多的会遇到类似的gui重入,或者反向调用, 因此在有条件的时候可以考虑。
void mayreentrymethod(..)
{
printinfo(entercnt , enter_tid);
// somelogi.....
printinfo(leavecnt , leave_tid);
}
也许是个不错的debug选择,当然最好是估计到这种情况,并且处理它。
2008-11-27 发现的进程外com的线程模型问题
场景说明
1. ui线程中有人以 postmsg 方式发送了消息
2. 接受方有人以ui/sync模式需要接受此消息
3. 此接受这在处理过程中,需要调用进程外com对象的configitemstub->OnDestroy方法通知对方销毁。
运行过程分析
1. 当消息总线接受到post后,丢到了一个worker,然后令调用者直接返回,这就是post的道理。
2. worker接受到后,如果看到 !sync 标记那么就想目标gui线程postmsg,然后返回;否则就sengmsg给ui线程然后基于windows提供同步等待机制。(见下面的说明)
3. ui线程中收到消息后,直接找到处理过程proc,然后继续调用。
4. msgproc在ui线程中被触发,然后调用configitemstub->OnDestroy ,结果由于是发送了进程外com调用因此实际上又出现了sendmsg调用。 结果这个时候出现了问题。 0x8001010d
说明:
估计windows sendmsg 的内部实现是如果发现调用者和自己同线程那么直接进行不做其他处理;否则创建一个内部事件,然后当处理完成后将此事件触发通知调用者,因此可以分析上面的案例中,由于sendmessage已经被调用,此事件一经被使用,而后来又出现了一次sendmsg windows发现已经发生来重入,因此发出
0x8001010d错误.
阅读(770) | 评论(0) | 转发(0) |