Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步循环中的Null引用,但对象没有Null_C#_Multithreading_Thread Safety - Fatal编程技术网

C# 异步循环中的Null引用,但对象没有Null

C# 异步循环中的Null引用,但对象没有Null,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,首先,这个问题没有得到回答,因为它描述了简单/基本的对象引用问题。我所经历的与多线程异步处理有关,而另一篇文章并没有解决这个问题 我有一个多线程的.NET winforms应用程序,我正在这样做: if ( paramList != null ) { lock ( paramList ) { foreach ( DictionaryEntry param in paramList ) { command.Parameters.AddWithValue(para

首先,这个问题没有得到回答,因为它描述了简单/基本的对象引用问题。我所经历的与多线程异步处理有关,而另一篇文章并没有解决这个问题

我有一个多线程的.NET winforms应用程序,我正在这样做:

if ( paramList != null ) {
   lock ( paramList ) {
      foreach ( DictionaryEntry param in paramList ) {
         command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
      }
   }
}
paramList是一个OrderedDictionary

我偶尔会在foreach行上发现这个错误:

对象引用未设置为对象的实例

如您所见,param.Key为null,param.Value为null。但这毫无意义,因为paramList中没有空值,正如您在这里看到的:

在屏幕截图中,您只能看到索引2,但我检查了索引0和1,同样的,也检查了有效数据,没有空值

我没有使用多线程应用程序的经验,但由于中的响应,我将该块锁定。在放入锁之前,我偶尔会发现错误集合被修改了;枚举操作不能执行。在锁定之后,错误消失了,但是现在我得到了如上所示的对象引用

我能做些什么来解决这个问题

编辑

根据几张海报的建议,我这样做了:

private static object syncLock = new object();
然后在用法上向下:

lock ( syncLock ) {
   if ( paramList != null ) {
       foreach ( DictionaryEntry param in paramList ) {
          command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
       }
   }
}
这似乎解决了对象引用错误,谢谢大家,但现在我偶尔得到:

收集被修改;枚举操作不能执行

因为在尝试这种新方法后,我遇到了一个完全不同的错误。我不确定这样做是否正确,因为现在看来这些问题是相关的,我只是看到同一个核心问题的不同症状


如果有人有想法,仍在寻找解决方案。

您的代码将无法工作。如果在null检查期间它不是null,但是在锁定时它是null呢

。对象_mutex=新对象;已经成为习惯

编辑:暗示为私有,但您可能希望按照Charles的建议将其设置为只读

如果锁定变量/字段,可能会遇到此问题。或者原语的装箱没有任何作用,因为原语总是放在不同的盒子里。或者其他人试图锁定调用堆栈,导致死锁

示例代码:

//_mutex is private, readonly and exist exclusively for this operation
lock(_mutex){
  //You only do null checks after you got a lock
  if ( paramList != null ){
    foreach ( DictionaryEntry param in paramList ) {
      command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
    }
  }
}
所有其他读取、写入或处理变量paramList、其任何字典实体及其字段(包括任何副本*)的代码也需要在锁互斥中。所以它们不能相互碰撞

*基本类型和字符串的副本是例外。内置基元类型是不可变的。通常也不要使用参考力学。String类也被设置为inmutable,以允许它以这种方式工作

首选更改参数列表,这样就不需要锁定它

如果您需要分享,那么:

锁定不变的对象,例如私有只读对象l=新对象;,或专用静态只读(如果需要)。 检查填充参数列表的代码是否也已锁定。
这是解决我所有问题的解决方案:

var connection = getConnectionFromPool(sourceOrDC);

try {
   lock ( connection ) {
      using ( SqlCommand command = new SqlCommand(sql, connection) ) {
         command.CommandType = CommandType.Text;

         if ( paramList != null ) {
            foreach ( DictionaryEntry param in paramList ) {
               command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
            }
         }

         command.CommandTimeout = 0;
         command.ExecuteNonQuery();
      }
   }

   return true;
}

我必须将更多的代码放入锁中,并锁定连接。

尝试锁定不同的对象,而不是参数列表查看示例:通常您想要一个:private readonly object myLock=new对象,如果您试图保护的是类变量。否则使锁静止。第二:在AddWithValue之前测试null。第三,您需要在访问参数列表的任何位置使用锁,如果您在此处锁定,但未在添加或删除某些内容的其他位置锁定,则会出现此错误。这是否回答了您的问题?我认为您正处于一个痛苦的世界中,因为您开始使用多线程,但对概念的理解还不够透彻。如果你有时间阅读,这是一个很好的资源:约瑟夫·阿尔巴哈里。我真的很困惑为什么这被否决了。我甚至不是海报!我不明白你的建议。你能根据我发布的代码给出示例代码吗?@Herrmancoder:这是不受欢迎的,我不喜欢复制其他海报作品,但这基本上和我说的一样——使用锁。不过,我确实添加了一些链接和更多解释。所以我觉得没关系,我不明白你的意思。您能根据我发布的代码给出示例代码吗?尝试并运行后,我现在得到的集合已被修改。@HerrimanCoder:Foreach不处理集合,只处理枚举数。转换是隐式完成的,但枚举数有一个规则:如果您重复发送了一个集合,而基础集合发生了更改,则枚举数必须变为无效,并抛出该例外@HerrimanCoder:所以有两个选项:1您没有告诉我们此代码的功能类似于从集合中删除元素2其他一些代码在foreach循环中更改paramList。Wich清楚地说,另一个代码不在lock语句中。您是否忘记了从放入paramList的实例中读取或删除的一些代码?