Problem with counting in threads

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,464
Location
Norway
Programming Experience
10+
I have this sample structure that holds linecount of a file:
VB.NET:
Private Structure TestCount
    Public Property Lines As Integer
  
    Public Shared Function CountFile(file As String) As TestCount
        Return New TestCount With {.Lines = IO.File.ReadAllLines(file).Count}
    End Function

    Public Shared Operator +(a As TestCount, b As TestCount) As TestCount
        Return New TestCount With {.Lines = a.Lines + b.Lines}
    End Operator
End Structure
Then I have parallel loop to add count of multiple files, this is done in two ways; one adds count to totalA, the other adds each count to a list:
VB.NET:
Public Shared Async Sub Test()
    Dim totalA As TestCount
    Dim counts As New List(Of TestCount)
    Dim files = IO.Directory.GetFiles("J:\projects\SomeFolder", "*.vb", IO.SearchOption.AllDirectories)
    Await Task.Run(Sub() Parallel.ForEach(files, Sub(file)
                                                     totalA += TestCount.CountFile(file)
                                                     counts.Add(TestCount.CountFile(file))
                                                 End Sub))
    Dim totalB = counts.Aggregate(Function(x, y) x + y)
    Debug.WriteLine($"totalB: {totalB.Lines}") 'always correct
    Debug.WriteLine($"totalA: {totalA.Lines}") 'why less count?
End Sub
totalB which is the sum of all counts in list is always correct, totalA is not - why is that?

If I change totalA += TestCount.CountFile(file) to this:
VB.NET:
Dim filecount = TestCount.CountFile(file)
totalA += filecount
then totalA is also always correct. Why the need for a local variable here?

By the way, the counts list and totalB is only added here to show correct count for comparison, I don't want this in the actual code, I only want the totalA += part, but fail to see why I have to first assign result to variable before adding it to total. Anyone?

VS 2019 and .Net 4.7 if it matters.
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,464
Location
Norway
Programming Experience
10+
Using SyncLock on totalA += assignment should probably be done here, or using thread-safe Add method in structure with totalA.Add(TestCount.CountFile(file)) in loop.
VB.NET:
Public Sub Add(value As TestCount)
    Threading.Interlocked.Add(Lines, value.Lines)
End Sub
 
Top Bottom