Reputation: 131
I have a block of code that is reading from a queue, processing one item (in its own thread), and then repeating until the queue is empty.
public ActionResult GetOrdersAsync() {
int count = 0;
SyncDM sync = _common.StartSync();
while (sync != null && sync.SyncId != 0) {
int customerId;
bool result = int.TryParse(sync.Payload, out customerId);
if (result) {
Task.Run(() => GetOrders(sync.SyncId, customerId));
}
count++;
//Process the next Sync
sync = _common.StartSync();
}
return Json(new JsonModel {
Message = "Started " + count + " instances of GetOrders",
Success = count > 0
});
}
StartSync() either removes an item from the queue, or returns null if the queue is empty. GetOrders() processes the object.
The problem is that sometimes the code raises a NullReferenceException on this line Task.Run(() => GetOrders(sync.SyncId, customerId));
In the debugger, Sync is null
(reason for exception), but customerId has a value. This tells me sync had a value on the previous line. This is confusing me, I'm thinking it has something to do with Task.Run and threading but I don't understand how a locally scoped variable is spontaneously changing its value.
Upvotes: 3
Views: 103
Reputation: 27367
You're updating the reference of sync
before your task gets a chance to operate on it. Note that tasks don't necessarily start immediately. In some cases, your task may start after the following is executed further down:
sync = _common.StartSync();
Now your reference to sync
is potentially null, and when your task goes to access sync.SyncId
, you get a null reference exception.
Change your code to the following:
if (result) {
var syncId = sync.SyncId;
Task.Run(() => GetOrders(syncId, customerId));
}
This works because we just want to pass in the Id. What if you wanted to pass in the object itself? You'd need to create a new variable which will not be modified outside of the closure:
if (result) {
var capturedSync = sync;
//Assuming GetOrders now takes a `Sync`
Task.Run(() => GetOrders(capturedSync, customerId));
}
Upvotes: 6