Null reference in async loop, but object has no nulls

被刻印的时光 ゝ 提交于 2020-01-06 08:13:40

问题


First, this is not answered by this SO post, as that describes simple/basic object reference problems. What I'm experiencing is related to multithreaded async processing, which the other post doesn't solve.

I have a multithreaded .NET winforms app and I'm doing this:

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

paramList is an OrderedDictionary.

I sporadically get this error on the foreach line:

Object reference not set to an instance of an object.

As you can see, param.Key is null and param.Value is null. But this makes no sense because there are no nulls in paramList, as you can see here:

In the screenshot you can see only index 2, but I examined index 0 and 1 also, same thing, valid data, no nulls.

I'm not experienced with multithreaded apps, but I put that block in a lock() due to responses in this SO post. Before putting in the lock() I was sporadically getting the error Collection was modified; enumeration operation may not execute. After putting in the lock, that error went away, but now I'm getting the object reference as shown above.

What can I do to solve this?

EDIT

Taking the advice of a few posters, I did this:

private static object syncLock = new object();

and then down in the usage:

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

That seems to have solved the object reference error (thanks everyone), but now I sporadically get:

Collection was modified; enumeration operation may not execute.

Because I got a completely different error after trying this new approach, I created a new SO question. I'm not sure if that was the right thing to do because now it seems these problems are related and I'm just seeing different symptoms of the same core problem.

Still looking for a solution if anyone has ideas.


回答1:


(Preferred) Change your paramList so you don't need to lock it.

If you need to share then:

  1. Lock on a object that doesn't change e.g. private readonly object l = new object();, or private static readonly, if needed.
  2. Check that the code that fills paramList is also locked.



回答2:


Your code will not work. What if it was not null during the null check, but is null when you come to the lock?

There is the standing advise to always have a dedicated thing to lock onto. A object _mutex = new object(); has become customary.

Edit: Private is implied, but you propably want to make it readonly as Charles suggested.

If you lock on variables/fields, you might run into this issues. Or boxing of primitives (wich does not do anything, because primitves are always put into different boxes). Or somebody else trying to lock it up the call stack, causing a deadlock.

Example code:

//_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);
    }
  }
}

All other code reading, writing or processing the variable paramList, any of it's Dictionary entires and their fields - including any copies* - also need to be in a lock(_mutex). So they can not collide with one another.

*copies of primitive types and string are the exception. Builtin Primitive types are inmutable. Also do not usually use reference mechanics. And the String class was also made inmutable, to allow it to work this way




回答3:


This is the solution that solved all my problems:

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;
}

I had to enclose more of the code in lock(), and lock the connection.



来源:https://stackoverflow.com/questions/58784691/null-reference-in-async-loop-but-object-has-no-nulls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!