6

NullReferenceException is being thrown on a line on which all involved objects are valid. StackTrace shows the line # is 432.

The code is

enter image description here

Here, Flags and tempFlags both are datatables. Data types of columns of both datatables are primitive (decimal, datetime, short). The application is a multithreaded application and the code snippet belongs to the thread function. Flags is decalred at instance level i.e. shared to all threads while tempFlags is declared inside the thread function.

Here at this particular instance of time the Flags contains 1946 records and tempFlags contains 1. So, why is this NullReferenceException ??

Edit # 1

ex.InnerException
null
ex.StackTrace
at System.Data.DataTable.RecordStateChanged(Int32 record1, DataViewRowState oldState1, DataViewRowState newState1, Int32 record2, DataViewRowState oldState2, DataViewRowState newState2)
at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID)
at System.Data.DataTable.MergeRow(DataRow row, DataRow targetRow, Boolean preserveChanges, Index idxSearch)
at System.Data.Merger.MergeTable(DataTable src, DataTable dst)
at System.Data.Merger.MergeTableData(DataTable src)
at System.Data.Merger.MergeTable(DataTable src)
at System.Data.DataTable.Merge(DataTable table, Boolean preserveChanges, MissingSchemaAction missingSchemaAction)
at System.Data.DataTable.Merge(DataTable table)
at [...].cs:line 432"
ex.Data
    {System.Collections.ListDictionaryInternal}
        [System.Collections.ListDictionaryInternal]: {System.Collections.ListDictionaryInternal}
        IsFixedSize: false
        IsReadOnly: false
        Keys: {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}
        Values: {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}
ex.Message
"Object reference not set to an instance of an object."
ex.Source
"System.Data"

Edit # 2

It looks the Merge statement is not thread safe as after putting line 432 inside a lock, the exception is gone, SO FAR.

bjan
  • 2,000
  • 7
  • 32
  • 64

3 Answers3

4

Whenever you get NullReferenceException from within the framework and you're multithreading, it's almost certainly a thread-safety issue where you are not applying locks where you should be.

Andrew Arnott
  • 80,040
  • 26
  • 132
  • 171
  • It is slowing me down just because the framework's long living function is not thread safe !!! – bjan Jan 02 '13 at 05:46
  • 2
    @bjan Unless the objects claim to be thread-safe in the documentation, they cannot safely be used as such without the correct locks/barriers/precautions. *This is no different than the 99+% of code that I (or you) write that is not thread-safe because it was not meticulously designed to be.* Don't blame code that is used outside of its contractual bounds. (I would only allow one thread to access the DT at any time via a simple lock - or better, only let one thread "own" a DT at any given time - and see if that "fixes" the problems observed. Working >> "Fastest".) –  Jan 02 '13 at 06:02
2

Since it appears to be happening when inserting a new row, System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID) I would guess there is a constraint saying a field cannot be null. And you are trying to insert a null from the source table.

Or, there is a calculated column and one of the input columns is null.

Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
  • This [answer](http://stackoverflow.com/a/490569/649524) suggests preventive measures for this problem. – Tilak Jan 02 '13 at 05:39
1

Explanation of this exception (IMO) specific to this piece of code.

Lets us say thread A is executing Merge and passes the datatable Dt1 which is stored in Merge as referenceToDatatable, meanwhile

Thread B comes in and passes Dt2 to Merge which is stored in Merge as referenceToDatatable (the reference is same because non-primitive objects are passed by refernce, Merge is not thread safe and there is no Lock) and hence the Dt1 is overwritten by Dt2.

No exception so far because Dt2 is of same structure and it is not null.

Now thread B is suspended and thread A comes in, completes the Merge and exits, hence nullifies Dt1 which nullifies referenceToDatatable as well.

Now thread B comes in and finds referenceToDatatable = null -> Exception

bjan
  • 2,000
  • 7
  • 32
  • 64