相关IComMethodEvents

10

在实现IComMethodEvents时,你将得到三个事件:

  1. OnMethodCall
  2. OnMethodException
  3. OnMethodReturn

我的目标是记录COM+组件中每个方法的调用时间。

可以通过在COMSVCSEVENTINFO结构中使用 lTimelMicroTime 获取事件的时间,因此通过在OnMethodCallOnMethodReturn中记录时间,我应该能够计算出调用时间,但如何确保这两个事件相关呢?

通过测试,看起来我应该能够使用即时(JIT)激活的对象oid

这样做可能会有问题吗?还是有其他方法?

可能存在的一个问题是,我发现oid经常被重用,因此如果由于某种原因事件的顺序发生了变化,那么实现关联可能会更加困难。

更新1:

进一步测试表明,在多用户场景下仅使用oid是不够的。同一对象在同一时间被使用,因此至少需要使用oid原始调用者来进行关联。后续问题是:如何从COM+事件订阅程序获取原始调用者?

更新2:

刚发现了 IComMethod2Events。不同之处在于事件具有执行调用的线程标识符。测试看起来很有前途,我想象不出任何相关性错误的情况。COM+组件的线程模型为 Any Apartment

更新3

在这篇文章Creating COM+ PerfMon Counters to Monitor COM+ Data中使用了 oid。我认为在多线程公寓中这是不够的。

注:最终我将在Delphi中实现这个,所以我添加了Delphi标签。我也添加了C#标签,因为实现接口所使用的语言可能根本不重要。 更新:暂时添加c++标签,只是为了吸引那些真正使用过这些东西的人的注意。


一个用于监视COM+事务的工具:AppMetrics。也许很有用,你可以弄清楚他们如何进行监视。 - LU RD
这个页面可能也会有所帮助,MSDN COM+ Tracking - LU RD
@LURD 感谢提供链接。我从MSDN链接中了解了一些信息,COM+仪表化最终会引导你到Q中的事件。COM+跟踪将允许您获取COM+为您收集的数据,但只能下到组件级别(我想)。 - Mikael Eriksson
2个回答

3
如果事件由于某种原因以错误的顺序触发,COM+系统事件发布程序将使用COM+事件服务来触发这些事件。从事件发布者的角度来看,调用事件是同步的。当发布者触发一个事件时,在所有订阅者处理已触发的事件之前,它不会继续进行下一个事件。很自然地,匹配的OnMethodCall事件发生之前,不会发布OnMethodReturn/OnMethodException事件。我记得阅读有关COM+事件中竞态条件/断开订阅的知识库(KB)文章。据我所知,所有这些漏洞都在Windows 2000的各种服务包中得到了解决。尽管如此,我承认我没有试图在这个领域保持最新状态。
当实现IComMethod2Events时,您订阅与IComMethodEvents相同的瞬态订阅。因此,已触发事件的顺序也相同。
因此,必须使用至少oid和original caller来进行相关性检查。目前我真的不确定您是否正确解释了测试结果。您是如何进行测试的?
在具有JIT和池的“多客户端”场景中,oid应已封装了所需的所有信息。上次我实现这样的事件侦听器(已经有一段时间了),依赖于oid效果很好。虽然我的环境中的大部分组件都是用VB6编写的(因此在STA中生存),但即使在STA中,您也可以拥有单个线程的各个执行阶段的几个调用。由于COM+ STA线程池中的线程数存在上限,因此可能出现以下情况:调用A在特定线程上开始,调用B在同一线程上开始,调用B返回,调用A返回。我不记得有任何问题在没有“关于调用者的一些其他信息”的情况下通过oid跟踪调用。
您考虑的实现思路在很大程度上是规范的。附带平台SDK的COM+ spy示例使用oid参数跟踪每个调用。您可以在

感谢您提供答案。您在质疑我的测试时是正确的。我无法重现之前看到的内容,所以我可能之前犯了一个愚蠢的错误。我认为我在第一次调用之前看到了一个 oid 的第二个 call 事件,然后才有了 return 事件。 - Mikael Eriksson

1

MSDN链接 "Creating COM+ PerfMon Counters to Monitor COM+ Data" 看起来可以做到你想要的(尽管是用托管C ++实现的)。

我猜这部分内容是关键:

void IComMethodEvents.OnMethodCall(ref COMSVCSEVENTINFO ei, ulong
    lObjID, ref Guid gClsID, ref Guid gIID, uint nIndex)
{
    //Make sure that monitoring is enabled and that our performance
    //counter has been initialized.
    if (Monitor && pcMethodDuration != null)
    {
    try
    {                    
        //We are going to store the initial value in a Sorted List 
        //collection. To do this we are going to need a key that
        //represents this call.
        string strKey = lObjID.ToString() + gClsID.ToString() + 
            gIID.ToString() + nIndex.ToString();

这可能是您对oid(在他们的示例中为lObjID)思考的解决方案。不知道这是否涵盖了您的多用户场景,您需要尝试一下。该页面对此主题有相当多的细节,希望您能够弄清楚。祝好运。


1
是的,那篇文章就是我在问题的第三次更新中提到的。我认为这样做不起作用。真正好的是有一些关于为什么添加了IComMethod2Events接口的文档。我怀疑它是为了解决MTA中的相关性问题,但我没有找到任何相关信息。 - Mikael Eriksson
啊,抱歉 - 你是对的。 :) 我错了。我没有使用那个接口的经验,所以无法帮助你,但我建议制作一个简单的多线程应用程序并测试所提到的方法(“创建COM+ PerfMon计数器...”),看看它是否按预期工作。怎么样? - Per Lundberg
是的,我刚刚又尝试了一下,并得到了不同的结果,正如您可以在对另一个答案的评论中看到的那样。第一次测试时我一定犯了一个愚蠢的错误。谢谢您花费时间回答我的问题。 - Mikael Eriksson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接