locked
Tasks not taking integer argument by reference RRS feed

  • Question

  • I would expect the following code to print integers from 0 to 10, in a random order, followed by "done!".

    Module Module1
    
        Sub Main()
            Dim i As Integer = 0
            Dim tasks As New List(Of Task)
            For j As Integer = 0 To 10
                Dim t As New Task(Sub() PrintMe(i))
                t.Start()
                tasks.Add(t)
                i += 1
            Next
            For Each item As Task In tasks
                item.Wait()
            Next
            Console.WriteLine("done!")
        End Sub
    
        Sub PrintMe(ByVal id As Integer)
            Console.WriteLine(id)
        End Sub
    
    
    End Module

    However, what happens is rather disturbing:

    9
    9
    10
    10
    9
    9
    10
    11
    9
    11
    11
    done!
    Press any key to continue . . .

    As if the Tasks don't accept the value of the variable i by reference ...

    Can somebody tell me what's going wrong here?  I'm running VS 2013 Update 4 targeting .NET 4.5


    • Edited by Kevin8264 Friday, September 30, 2016 4:29 PM typo
    Friday, September 30, 2016 4:28 PM

Answers

  • I think that your code shows that the variable i is shared between tasks, i.e. it is a kind of reference to a common value.

    The details are explained in Visual Basic Language Specification (https://msdn.microsoft.com/en-us/library/ms234437.aspx) related to lambdas and closures. Lambda captures a new copy of a local variable each time it enters a block. Therefore, in order to have different values in the tasks, define a copy inside the For block:

        For j As Integer = 0 To 10

            Dim copy = i

            Dim t As New Task(Sub() PrintMe(copy))
            . . .

    Now each Sub lambda and the task will deal with a separate number, unaffected by other tasks.


    Friday, September 30, 2016 7:01 PM