我有一个非常详细的字典,存储350个密钥,每个密钥是一个3字节的字节数组。这本词典用于解释家庭酿造硬件的传入数据。
在对应用程序进行压力测试时,我遇到了一个奇怪的错误,它告诉我有一个KeyNotFoundException
。奇怪的是,密钥出现在字典中,我正盯着它。该词典使用了一个特殊的比较器,这可能是问题的原因:
private static Dictionary<byte[ ], string> PlayerMap =
new Dictionary<byte[ ], string>( new ByteArrayComparator( ) );
public class ByteArrayComparator : IEqualityComparer<byte[ ]> {
public bool Equals( byte[ ] left, byte[ ] right ) {
if ( left == null || right == null )
return left == right;
return left.SequenceEqual( right );
}
public int GetHashCode( byte[ ] Key ) {
if ( Key == null )
throw new ArgumentNullException( "Key" );
return Key.Sum( B => B );
}
}
只有当我模拟用户以疯狂的速度按下按钮时才会发生这种情况,这意味着正在多次多次查询字典。
为什么会这样?比较器有问题吗?
为了清楚起见,控制器以异步方式运行(因为它需要能够处理来自多个不同源的传入数据)。我不想发布控制器的所有源代码,因为它有很多,其中一些是敏感的,但我会发布这两个处理控件初始化的方法,以及它监听传入数据的方法: / p>
private static void Initialize(
string DevicePath,
R3Controller.HIDP_CAPS Capabilities,
R3Controller.HIDD_ATTRIBUTES Attributes ) {
R3Controller.hRead = R3Controller.OpenDevice( DevicePath );
R3Controller.hWrite = R3Controller.OpenDevice( DevicePath );
R3Controller.fsRead = new FileStream( hRead, FileAccess.ReadWrite, Capabilities.OutputReportByteLength, false );
R3Controller.fsWrite = new FileStream( hWrite, FileAccess.ReadWrite, Capabilities.OutputReportByteLength, false );
if ( R3Controller.fsRead.CanRead ) {
R3Controller.barData = new byte[R3Controller.devCapabilities.Value.InputReportByteLength];
if ( R3Controller.fsRead.CanRead )
R3Controller.fsRead.BeginRead( R3Controller.barData, 0, R3Controller.barData.Length,
new AsyncCallback( R3Controller.Listen ), R3Controller.barData );
else
throw new Exception( "R3 Controller Can't Read Incoming Data" );
}
}
private static void Listen( IAsyncResult IAR ) {
R3Controller.fsRead.EndRead( IAR );
if ( R3Controller.fsRead.CanRead )
R3Controller.fsRead.BeginRead( R3Controller.barData, 0, R3Controller.barData.Length,
new AsyncCallback( R3Controller.Listen ), R3Controller.barData );
else
throw new Exception( "R3 Controller Can't Read Incoming Data" );
R3InputEventArgs Args = new R3InputEventArgs( R3Controller.barData );
if ( R3Controller.Locked || R3Controller.LockedControllers.Contains( Args.Controller ) ) {
//Respond to locked presses if necessary...
if ( R3Controller._LockedFeedback != null )
R3Controller._LockedFeedback( null, Args );
/*GetInvocationList( ).ToList( ).ForEach( E => (
E.Clone( ) as EventHandler<R3InputEventArgs> ).BeginInvoke( null, Args, R3Controller.Heard, null ) );*/
} else if ( R3Controller._ButtonPressed != null )
R3Controller._ButtonPressed(null, Args);/*.GetInvocationList( ).ToList( ).ForEach(
E => ( E.Clone( ) as EventHandler<R3InputEventArgs> ).BeginInvoke( null, Args, R3Controller.Heard, null ) );*/
}
答案 0 :(得分:1)
如果您在相同/关闭时间执行读取和写入操作,Dictionary
类本身并不是线程安全的。因此,如果很多线程非常快速地访问它,您可能会遇到各种有趣的问题。既然你提到这只会在你很快执行操作时发生,那么很有可能是问题所在。 据我所知,只执行没有写入的读取不应该导致Dictionary
出现任何问题。
如果您使用的是.NET 4+,则Dictionary
的线程安全版本称为ConcurrentDictionary,仅适用于此类情况。