vb.net Code:
  1. For each currentFarm in ...
  2. ...
  3.                 If urlQueue.Count > 0 Then
  4.                     Debug.Assert(currentFarm.isBusy = False)
  5.                     Debug.Assert(currentFarm.WebClient.IsBusy = False)
  6.                     ExecuteThread(urlQueue.Dequeue, currentFarm)
  7.                     'currentFarm.PackedScannable = urlQueue.Dequeue
  8.                     'currentFarm.Thread = New System.Threading.Thread(Sub() beginThreadAction.Invoke(currentFarm.PackedScannable, theFarm))
  9.                     'currentFarm.Thread.Start()
  10.                     'webClientFarm.currentFarm.getURL(urlQueue.Dequeue)
  11.                     OneOfThemBusy = True ' this time the current farm must be busy because we just told them to grab a new URL right? so at least one of them is busy
  12.                 End If
  13. ...
  14. next currentFarm
  15.  
  16.     Public Shared Sub ExecuteThread(ByVal PackedScannableParameter As String, ByVal theFarm As enchancedWinClient)
  17.         theFarm.PackedScannable = PackedScannableParameter
  18.         theFarm.Thread = New System.Threading.Thread(Sub() beginThreadAction.Invoke(PackedScannableParameter, theFarm))
  19.         theFarm.Thread.Start()
  20.     End Sub

The commented code won't work. That's because by the time the thread start, the variable currentFarm have changed.

So I create a new function and cache the currentFarm in the function parameter. No there will be a cache of currentFarm address (object is always a pointer) on a stack and that address is the one being passed to the System.Threading.Thread constructor.

Tada problem solved.