嵌套多线程操作跟踪

2024-03-03

我有一个类似的代码

void ExecuteTraced(Action a, string message)
{
    TraceOpStart(message);
    a();
    TraceOpEnd(message);
}

回调 (a) 可以再次调用 ExecuteTraced,并且在某些情况下,异步调用(通过 ThreadPool、BeginInvoke、PLINQ 等,因此我无法显式标记操作范围)。我想跟踪所有嵌套操作(即使它们异步执行)。因此,我需要能够在逻辑调用上下文中获取最后跟踪的操作(可能有很多并发线程,因此不可能使用 lastTraced 静态字段)。

有 CallContext.LogicalGetData 和 CallContext.LogicalSetData,但不幸的是,当调用 EndInvoke() 时,LogicalCallContext 将更改传播回父上下文。更糟糕的是,如果 EndInvoke() 被异步调用,这种情况可能随时发生。EndInvoke 更改当前 CallContext - 为什么? https://stackoverflow.com/questions/883486/endinvoke-changes-current-callcontext-why

另外,还有Trace.CorrelationManager,但它基于CallContext并且有同样的麻烦。

有一个解决方法:使用 CallContext.HostContext 属性,该属性不会在异步操作结束时传播回来。此外,它不会克隆,因此该值应该是不可变的 - 这不是问题。不过,它由 HttpContext 使用,因此解决方法在 Asp.Net 应用程序中不可用。

我看到的唯一方法是将 HostContext (如果不是我的)或整个 LogicalCallContext 包装到动态中,并分派最后跟踪操作旁边的所有调用。


好吧,我自己回答。

短一:没有解决办法。

稍微详细一点:

问题是,我需要一种方法来存储每个逻辑上下文的最后一个活动操作。跟踪代码无法控制执行流程,因此不可能将 lastStartedOperation 作为参数传递。调用上下文可能会克隆(例如,如果另一个线程启动),因此我需要将值克隆为上下文克隆。

CallContext.LogicalSetData() 很适合,但它会在异步操作结束时将值合并到原始上下文中(实际上,替换调用 EndInvoke 之前所做的所有更改)。从理论上讲,它may甚至异步发生,导致 CallContext.LogicalGetData() 产生不可预测的结果。

我说理论上是因为 asyncCallback 内的简单调用 a.EndInvoke() 不会替换原始上下文中的值。不过,我没有检查远程调用的行为(看起来,WCF 根本不尊重 CallContext)。另外,文档 http://msdn.microsoft.com/en-us/library/w61s16a1(VS.71).aspx(旧的)说:

BeginInvoke 方法传递 CallContext 到服务器。什么时候 调用EndInvoke方法时, CallContext 被合并回 线。这包括以下情况 调用 BeginInvoke 和 EndInvoke 依次和其中 BeginInvoke 是 在一个线程上调用,EndInvoke 是 调用回调函数。

最后一个版本不太明确:

BeginInvoke 方法传递 CallContext 到服务器。当。。。的时候 调用EndInvoke方法,获取数据 CallContext 中包含的内容是复制的 回到调用的线程 开始调用。

如果您深入研究框架源代码,您会发现值实际上存储在当前线程的当前 ExecutionContext 内的 LogicalCallContext 内的哈希表中。

当调用上下文克隆时(例如在 BeginInvoke 上),调用 LogicalCallContext.Clone。 EndInvoke(至少在原始 CallContext 中调用时)调用 LogicalCallContext.Merge(),用新值替换 m_Datastore 中的旧值。

因此,我们需要以某种方式提供将被克隆但不会合并回来的值。

LogicalCallContext.Clone() 还克隆(不合并)两个私有字段 m_RemotingData 和 m_SecurityData 的内容。由于字段的类型定义为内部,因此您无法从它们派生(即使使用发出),添加属性 MyNoFlowbackValue 并将 m_RemotingData (或另一个)字段的值替换为派生类的实例。

此外,字段的类型不是从 MBR 派生的,因此不可能使用透明代理来包装它们。

您无法从 LogicalCallContext 继承 - 它是密封的。 (注意,实际上,如果使用 CLR 分析 api 来替换 IL,就像模拟框架那样。这不是理想的解决方案。)

您无法替换 m_Datastore 值,因为 LogicalCallContext 仅序列化哈希表的内容,而不序列化哈希表本身。

最后的解决方案是使用 CallContext.HostContext。这有效地将数据存储在 LogicalCallContext 的 m_hostContext 字段中。 LogicalCallContext.Clone() 共享(而不是克隆) m_hostContext 的值,因此该值应该是不可变的。不过这不是问题。

如果使用 HttpContext,即使这样也会失败,因为它设置 CallContext.HostContext 属性来替换您的旧值。讽刺的是,HttpContext 没有实现 ILogicalThreadAffinative,因此不会存储为 m_hostContext 字段的值。它只是用 null 替换旧值。

因此,没有解决方案,也永远不会有解决方案,因为 CallContext 是远程处理的一部分,而远程处理已经过时了。

附: Thace.CorrelationManager 在内部使用 CallContext,因此也无法按预期工作。顺便说一句,LogicalCallContext 有特殊的解决方法来在上下文克隆上克隆 CorrelationManager 的操作堆栈。遗憾的是,它没有关于合并的特殊解决方法。完美的!

附言例子:

static void Main(string[] args)
{
    string key = "aaa";
    EventWaitHandle asyncStarted = new AutoResetEvent(false);
    IAsyncResult r = null;

    CallContext.LogicalSetData(key, "Root - op 0");
    Console.WriteLine("Initial: {0}", CallContext.LogicalGetData(key));

    Action a = () =>
    {
        CallContext.LogicalSetData(key, "Async - op 0");
        asyncStarted.Set();
    };
    r = a.BeginInvoke(null, null);

    asyncStarted.WaitOne();
    Console.WriteLine("AsyncOp started: {0}", CallContext.LogicalGetData(key));

    CallContext.LogicalSetData(key, "Root - op 1");
    Console.WriteLine("Current changed: {0}", CallContext.LogicalGetData(key));

    a.EndInvoke(r);
    Console.WriteLine("Async ended: {0}", CallContext.LogicalGetData(key));

    Console.ReadKey();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌套多线程操作跟踪 的相关文章

  • 在 Azure 上运行 .NET 应用程序

    我拥有在 Amazon EC2 上运行应用程序的丰富经验 它需要一台低端服务器 我目前为该服务器支付大约 90 美元 月 是的 我知道我并不真正需要可扩展性 但我仍然使用 EC2 我想知道将这个纯粹的 NET 应用程序迁移到 Microso
  • 有条件地在 Visual Studio 中嵌入资源 (C#)

    有没有办法有条件地将资源嵌入到 NET 项目中 IE 如果我定义了 INCLUDETHIS 那么我想要将某个大文件嵌入到 dll 中 否则我不希望它嵌入 我知道我可以做两个项目来做到这一点 但我希望在一个项目中完成这一切 使用该文件的代码很
  • 删除匹配前的一个单词和一个单词

    匹配之前的一个单词可以是一组任何符号 例如 D E F 我有一个正则表达式 s w s XXX 输入示例 This is KKK M D D xXx PPP输出示例 This is KKK PPP 所以我需要删除 XXX 之前的 1 个单词
  • 调试 Java InterruptedException,即查找原因

    在调试Android应用程序时 有时中断异常发生并使应用程序崩溃 我已经能够在默认异常处理程序上设置断点 但调用堆栈不提供信息 at java util concurrent locks AbstractQueuedSynchronizer
  • 从 Handler.obtainMessage() 获取什么参数

    我正在使用线程来执行一些 BT 任务 我正在尝试向 UI 线程发送消息 以便我可以基于我的 BT 线程执行 UI 工作 为此 我使用处理程序 但我不知道如何检索发送到处理程序的数据 要发送数据 我使用 handler obtainMessa
  • 记录共享和映射的诊断上下文

    据我所知 其他人做了什么来解决 Commons Logging 项目 针对 NET 和 Java 不支持映射或嵌套诊断上下文这一事实 执行摘要 我们选择直接使用实现者日志框架 在我们的例子中为 log4j 长答案 您是否需要一个抽象日志框架
  • 调用许多网络服务的最佳方式?

    我有 30 家子公司 每家都实施了他们的 Web 服务 使用不同的技术 我需要实现一个Web服务来聚合它们 例如 所有子公司的Web服务都有一个名为的Web方法GetUserPoint int nationalCode 我需要实现我的网络服
  • 这个等待通知线程语义的真正目的是什么?

    我刚刚遇到一些代码 它使用等待通知构造通过其其他成员方法与类中定义的线程进行通信 有趣的是 获取锁后 同步范围内的所有线程都会在同一锁上进行定时等待 请参见下面的代码片段 随后 在非同步作用域中 线程执行其关键函数 即 做一些有用的事情1
  • 在 Web 浏览器中禁用 F5 [重复]

    这个问题在这里已经有答案了 可能的重复 禁用浏览器的后退按钮 https stackoverflow com questions 961188 disable browsers back button 如何禁用浏览器上的 F5 刷新 htt
  • SQL 查询将文本数据存储在 Varbinary(max) 中

    有没有办法让 varbinary 在 SQL Server 中接受文本数据 这是我的情况 我有相当大量的 XML 我计划以 压缩 格式存储它们 这意味着 Varbinary 但是 当我进行调试时 我希望能够翻转配置开关并以纯文本形式存储 以
  • PyQt5:如何使QThread返回数据到主线程

    I am a PyQt 5 4 1 1初学者 我的Python是3 4 3 这是我尝试遵循的many https mayaposch wordpress com 2011 11 01 how to really truly use qthr
  • 如何使用 WebResponse 下载 .wmv 文件

    我使用以下代码通过 WebResponse 获取 wmv 文件 我正在使用一个线程来调用这个函数 static void GetPage object data Cast the object to a ThreadInfo ThreadI
  • 获取 System.Drawing.Font 宽度?

    我正在使用 Net 工具进行一些 2D 绘图 System Drawing Font uses a GetHeight 返回以像素为单位的高度 我缺少一个GetWidth 检索宽度 我应该用什么 Use Graphics MeasureSt
  • 奇怪的跨线程 UI 错误

    我正在编写一个 WinForms 应用程序 它有两种模式 控制台或 GUI 同一解决方案中的三个项目 一个用于控制台应用程序 一个用于 UI 表单 第三个用于保存两个界面也将连接的逻辑 控制台应用程序运行绝对流畅 保存用户选择的模型 它有一
  • MVC2 中隐藏字段的替代方案

    我有一个 viewModel 其中包含一个在传递给部分视图之前填充的字符串 我需要能够在发布表单时取回数据 目前我已经创建了一个隐藏字段并将数据绑定到它 然后 当回发时 我可以从表单集合中获取数据 这并不完全是我想要的 我希望数据完全隐藏在
  • 在 .Net 应用程序中使用 Active Directory Web 服务

    我正在尝试构建一个 Net 应用程序来询问 Active Directory 编辑 我需要使用 Web 服务来执行此操作 因为我将使用需要使用 Web 服务的第三方工作流工具从 Sharepoint 工作流与 AD 进行通信 根据我的研究
  • Api 控制器中长时间运行的任务(使用 Web API,自托管 OWIN)

    我想在自托管 OWIN 环境中的 ApiController 中运行长时间运行的任务 例如 4 5 分钟 但是 我想在开始该任务后 一旦开始长时间运行的任务 就发回响应 而不等待它完成 这个长时间运行的任务与 HTTP 无关 并且顺序运行一
  • C# 中 DLL 和命名空间的关系

    这里有一个高级问题 今天我花了很多时间自学基本的高级概念 例如 API 静态和动态库 DLL 以及 C 中的编组 获得所有这些知识让我想到了一个看起来非常基本的问题 并且可能表明我对这些概念的理解存在漏洞 我知道的 DLL 可能包含类 这些
  • 在不支持线程的程序加载的共享库中使用 C++11 多线程

    我目前正在尝试在共享库中使用 C 11 多线程 该库加载到 Linux 上的主程序 用 C 编写 中 这是一个大型模拟程序的一部分 我无法更改有关库加载的任何内容或更改一般的主程序 主程序是用 gcc 4 1 2 编译的 我没有它的源代码
  • string.Compare 行为

    怎么会这样呢 这是从VS2008中的立即窗口获取的 string Compare 1 string Compare 0 0 1 从言论来看字符串比较 http msdn microsoft com en us library 84787k2

随机推荐