1

我现在有一个事件处理器类,它有一个字典来存储所有订阅。事实上,它是一本词典词典。而这个进程类正在与第三方远程服务器进行通信以请求目标数据。我问这个问题是因为现在我们偶尔会遇到一些订阅丢失的问题。由于由于某种原因很难验证这种丢失是否发生在与远程服务器的连接中,所以我现在必须首先检查我的事件处理器类是否有任何问题。我的第一个怀疑是订阅信息是否由于此 Dictionary 对象的溢出而丢失。有人有什么主意吗?谢谢!

更新

也许我应该多谈谈这个场景,因为代码并不容易显示。我们曾经有我们的遗留软件,我们称之为 A,使用 B 的供应商提供的 API 与称为 B 的远程数据服务进行通信。但是,由于我们将 A 改为 64 位 SW,但为 B 提供的库仍然是 32 位,所以我们新的 64 位 A 不能再使用这个库了。因此,我正在设计一个名为 C 的 32 位 SW,以使用该库连接到 B,同时使用 WCF 与 64 位 A 保持通信。由于 C 主要是 pub/sub 结构,正如我之前提到的,我使用 Dictionary of Dictionary 来维护 C 中的请求和订阅。我们的问题来了:我们遇到了一些订阅丢失(很长时间没有发布,但是在重新初始化订阅后,我们可以在 A 处获得出版物)。我们不容易去查B的反馈,看看有没有配置错误。而且我的 WCF 服务日志也没有显示任何错误。我不得不怀疑问题仅发生在 C 上。我知道多线程问题,所以我锁定了字典的每个操作。但我就是想不出有什么问题。顺便说一句,它不像 C 那样内存用完并且 C 崩溃了。

4

2 回答 2

6

如果“溢出”是指“意外地默默丢失数据”,那么不,据我所知。

如果您的意思是“用完系统中的所有内存直到崩溃”,那么是的,这是可能的,但听起来不像发生在您身上的事情。

如果您在Dictionary<,>没有任何锁定的情况下使用来自多个线程的标准,可能会导致您丢失数据。ConcurrentDictionary<,>如果您使用的是 .NET 4,您应该使用锁定(小心!)或使用。

此外,如果您有任何您不期望的重复键,如果您使用索引器,这将用另一个条目覆盖一个条目的数据。(如果您使用该Add方法则不会 - 它会引发异常。

基本上我们一直在猜测,直到我们看到一些代码或至少获得更多上下文......

于 2012-07-06T19:03:37.297 回答
2

听起来像是比赛条件的秘诀。

你可能有一些看起来像这样的代码:

if (!myDictionary.ContainsKey(key))
{
  //point of interest
  myDictionary[key] = new Dictionary<X, Y>()
}
myDictionary[key][innerkey] = innnervalue;

问题是两个线程使它成为条件内的兴趣点注释。您真的不打算为同一个键运行该块两次,但是线程魔术使它发生。

  1. 线程 A 和线程 B 使其到达兴趣点。
  2. 线程 A 唤醒并运行该方法的其余部分。
  3. 线程 B 唤醒并运行,孤立线程 A 创建的字典。

您可以通过保护锁后的共享实例来解决此问题:

lock(_theLockInstance)
{
  if (!myDictionary.ContainsKey(key))
  {
    //point of interest
    myDictionary[key] = new Dictionary<X, Y>()
  }
  myDictionary[key][innerkey] = innnervalue;
}

现在,一次只有一个线程可以到达临界区,并且不会创建孤立字典。

于 2012-07-06T19:11:02.660 回答