Dictionary <TKey,TSource>的神秘行为

ILy*_*Lya 8 c# mono dictionary exception thread-safety

我正在开发一个基于Asp.net MVC 3.0并使用Mono-2.10.8(Windows 7)的庞大系统.

一切都很好,直到几天前.

在我的API中,我有几个使用字典的实用程序类.例如,像这样:

public static class KeyUtility  
{
  static KeyUtility() {
    Alphabet = new[] {
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
      'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 
      'T', 'U', 'V', 'X', 'Y', 'Z', '0', '1', 
      '2', '3', '4', '5', '6', '7', '8', '9'
    };

    ReverseAlphabet = Alphabet
      .Select((c, i) => new { Char = c, Value = i })
      .ToDictionary(k => k.Char, v => (byte) v.Value);
  }

  internal static char[] Alphabet;      
  private static IDictionary<char, byte> ReverseAlphabet;

  public static string ToKey(byte[] key, int groupSize)
  {
    //Accessing Alphabet to generate string key from bytes
  }

  public static byte[] FromKey(string key)
  {
    //Accessing ReverseAlphabet to get bytes from string key
  }
}
Run Code Online (Sandbox Code Playgroud)

随机我得到这样的例外:

System.IndexOutOfRangeException: Array index is out of range.
at System.Collections.Generic.Dictionary`2<char, byte>.TryGetValue (char,byte&) <0x000a1>
at MyAPI.KeyUtility.FromKey (string) <0x0009a>
at MyApp.Controllers.AboutController.Index () <0x002df>
at (wrapper dynamic-method) object.lambda_method (System.Runtime.CompilerServices.Closure,System.Web.Mvc.ControllerBase,object[]) <0x0002f>
at System.Web.Mvc.ActionMethodDispatcher.Execute (System.Web.Mvc.ControllerBase,object[]) <0x0001b>
at System.Web.Mvc.ReflectedActionDescriptor.Execute (System.Web.Mvc.ControllerContext,System.Collections.Generic.IDictionary`2<string, object>) <0x000ff>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod (System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor,System.Collections.Generic.IDictionary`2<string, object>) <0x00019>
at System.Web.Mvc.ControllerActionInvoker/<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12 () <0x00066>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (System.Web.Mvc.IActionFilter,System.Web.Mvc.ActionExecutingContext,System.Func`1<System.Web.Mvc.ActionExecutedContext>) <0x000b8>
Run Code Online (Sandbox Code Playgroud)

大多数时候一切都很好,KeyUtility工作正常,但在极少数情况下,我会得到这样的例外.尽管它看起来像线程安全问题,但字典ReverseAlphabet始终只能用于读取而不能用于写入.一旦在静态构造函数中创建它,它只能被访问TryGetValue.据我所知,从MSDN文章来看,在这种情况下它应该是线程安全的.而且,我之前没有见过这个问题.

我该怎么看?我甚至无法创作复制品,因为我完全不知道出了什么问题.

事实证明Mono-2.10.8及更早版本的字典是稳定的.我已经集中使用了几年,之前从未见过这种例外.

如何解决这个问题?

UPD:

我记得在麻烦开始的时候,我所做的就是静态链接单声道和我的可执行文件(我将单声道嵌入到我的应用程序中).我只是下载了mono的来源.除了我将libmono的输出设置为静态库之外,对其进行了编译而没有任何更改.我还链接了libeay32和sqlite3.所有多线程(MT).也许这种变化会影响应用程序?不幸的是我无法在独立单声道下检查这个.在此之前,我动态链接所有库,一切都很好.

UPD2: 以下是完整资源的链接:http://pastebin.com/RU4RNCki

Han*_*ant 12

我所做的是将静态链接单声道与我的可执行文件

你已经知道我认为的问题,肯定会破坏单声道.静态链接时不再发生的最重要的事情是,只要新线程在进程中开始执行,Windows就会生成DllMain()回调.这就是CLR如何意识到可能执行托管代码的线程.静态构造函数确实是一种可能的失败模式,必须阻止线程执行类中的任何代码,直到cctor()完成执行.如果它不知道线程,CLR就不能这样做.

如果你想使这个工作,那么你至少需要为你自己的DllMain()函数中的mono_thread_info_attach()调用提供一个替代方案.总的来说,我认为这是一个太多的优化.