If you are sure, that parsing is ALWAYS faster than reading, you can do it very simple:
Thread A (simply a thread to not block the UI-Thread) reads the file and then starts a new thread B and passes the file content to it (using Tasks instead of thread makes it easier). Put it into a loop and you are done.
Since the parsing is faster, the second thread/task will have finished before Thread A starts a new thread. So you will only have two threads running at the same time and 2 files in memory at the same time.
waiting for the obtaining-lines process to be completed. The parsing thread should know whether there is a ready to parse array.
Not sure if I understand it correctly, but that would be solved by the above "solution". Because you always start a new thread/task, WHEN and only when the file has been read completely.
UPDATE: If processing is NOT (always) faster than reading, your could do it for example like this:
Private MaxTasks As Integer = 4
Private Async Sub ReadAndProcess(ByVal FileList As List(Of String))
    Dim ProcessTasks As New List(Of Task)
    For Each fi In FileList
        Dim tmp = fi
        Console.WriteLine("Reading {0}", tmp)
        Dim FileContent = Await Task.Run(Of Byte())(Function() As Byte()
                                                        Return File.ReadAllBytes(tmp)
                                                    End Function)
        If ProcessTasks.Count >= MaxTasks Then
            Console.WriteLine("I have to wait!")
            Dim NextReady = Await Task.WhenAny(ProcessTasks)
            ProcessTasks.Remove(NextReady)
        End If
        Console.WriteLine("I can start a new process-task!")
        ProcessTasks.Add(Task.Run(Sub()
                                      Console.WriteLine("Processing {0}", tmp)
                                      Dim l As Long
                                      For Each b In FileContent
                                          l += b
                                      Next
                                      System.Threading.Thread.Sleep(2000)
                                      Console.WriteLine("Done with {0}", tmp)
                                  End Sub))
    Next
    Await Task.WhenAll(ProcessTasks)
End Sub
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim ofd As New OpenFileDialog
    ofd.Multiselect = True
    If ofd.ShowDialog = Windows.Forms.DialogResult.OK AndAlso ofd.FileNames.Count >= 1 Then
        ReadAndProcess(ofd.FileNames.ToList)
    End If
End Sub
The idea (which as usually could be implemented in 4 dozen ways in .Net) is simply, that you schedule new processing tasks until you reach your self-set limit. If that is reached you "wait" until a task becomes ready and start a new one.
UPDATE2: With TPL lib it might look like:
Private Sub Doit()
    Dim ABProcess As New ActionBlock(Of Tuple(Of String, Byte()))(Sub(tp)
                                                                      Console.WriteLine("Processing {0}", tp.Item1)
                                                                      Dim l As Long
                                                                      For Each el In tp.Item2
                                                                          l += el
                                                                      Next
                                                                      System.Threading.Thread.Sleep(1000)
                                                                      Console.WriteLine("Done with {0}", tp.Item1)
                                                                  End Sub, New ExecutionDataflowBlockOptions With {.MaxDegreeOfParallelism = 4, .BoundedCapacity = 4})
    Dim ABRead As New ActionBlock(Of String())(Async Sub(sarr)
                                                   For Each s In sarr
                                                       Console.WriteLine("Reading {0}", s)
                                                       Dim t = New Tuple(Of String, Byte())(s, File.ReadAllBytes(s))
                                                       Dim taken = Await ABProcess.SendAsync(t)
                                                       Console.WriteLine("Output taken = {0}", taken)
                                                   Next
                                                   Console.WriteLine("All reading done")
                                               End Sub)
    Dim ofd As New OpenFileDialog
    ofd.Multiselect = True
    If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
        ABRead.Post(ofd.FileNames)
    End If
End Sub
Which version is "nicer" ... might be personal taste ;) Personally I might prefer the "manual" version, because the new TPL Blocks are sometimes VERY blackboxish.