Link to home
Start Free TrialLog in
Avatar of AidenA
AidenA

asked on

vb.net threading

Hi, I am new to threading and wanted to see how I could implement into one of my windows apps. So I do something like that shown below (running the same sub mySub from different threads).

But, as soon as I start to do that, I realise that I've no idea what that it's actually going to do exactly and I'm sort of thinking 'how could that possibly work'. I'm thinking these threads are going to intefere with eachother and perhaps I should be starting three instances of the class with sub mySub instead of having three threads working on the same sub in the same class? I'm assuming all the variables would keep getting reset by the different threads so passing the parameters becomes pointless (i.e. you pass the parameter blnRateAll which is set to True for thread one, but then thread 2 starts up and sets it False for instance, and now thread 1 see's it at False instead of True?).

So, how exactly would you want to set something like this up? Three threads running the same subroutine? Also, I'm getting cross thread errors with SelectSheet which is another form. For instance, it can't set lstSelectSheet itself because of the cross thread error. I had previously found some code creating a delegate sub to invoke the label on that form no matter what thread called it which seemed to work ok, so I guess I would have to do something similar again?


Sub ThreadStart()

      Dim alParam As New ArrayList
      Dim paramTS As New ParameterizedThreadStart(AddressOf mySub)
      Dim t1 As Thread = Nothing
      Dim t2 As Thread = Nothing
      Dim t3 As Thread = Nothing

      'Create parameter array for the thread
      Dim d1 As New SelectSheet
      d1.lblSelectSheet.Text = "Please put in file 1 name"
      d1.ShowDialog()
      alParam.Add(d1.lstSelectSheet.SelectedItem.ToString())
      alParam.Add(True) 'for blnRateAll
      alParam.Add(True) 'for blnFirstPass
      alParam.Add(False) 'for blnSecondPass
      alParam.Add(False) 'for blnFinalPass
      d1.Dispose()

      t1 = New Thread(paramTS)
      t1.Start(alParam)


      Dim d2 As New SelectSheet
      d2.lblSelectSheet.Text = "Please put in file 2 name"
      d2.ShowDialog()
      alParam(0) = d2.lstSelectSheet.SelectedItem.ToString()
      alParam(2) = False : alParam(3) = True

      t2 = New Thread(paramTS)
      t2.Start(alParam)


      Dim d3 As New SelectSheet
      d1.lblSelectSheet.Text = "Please put in file 3 name"
      d3.ShowDialog()
      alParam(0) = d3.lstSelectSheet.SelectedItem.ToString()
      alParam(3) = False : alParam(4) = True

      t3 = New Thread(paramTS)
      t1.Start(alParam)


   End Sub

Open in new window

Avatar of kaufmed
kaufmed
Flag of United States of America image

Also, I'm getting cross thread errors with SelectSheet which is another form.
This is because you are trying to update the GUI from a thread other than the one the GUI was created on--typically, the main thread. You have to invoke a delegate in order to update your GUI from a different thread.

The big thing with threading is the management of shared resources and/or objects. Any time you have something being shared between threads, there is the potential to encounter deadlocks and race conditions. These scenarios are what you need to account for in your code. Most often, the way you handle this is through some sort of locking mechanism. This locking mechanism is what protects your critical section, the part of code that must only allow one thread to be executing at any given time, from multiple threads accessing the shared resources/objects.
Multithreading is a large subject, not something that can be explained in a mere answer. I would suggest reading Microsoft MSDN on the subject to get in-depth information.

Avatar of AidenA
AidenA

ASKER

yeah, have been reading a bit more there and this is where i am so far (see below).

So, i think i sort of got it working. Had to put synclock onto mySub to avoid the issues you mention, and then put the code below into my main function (and changed some things around to avoid th GUI issue... but I can solve that part I think)

That seemed to more or less solve the issue but I noticed that thread t3 was for some reason running before t2 which was causing a problem. That was ok, I can remove the reason why they must run in order. But, as a consequence, I need the application to wait at a particular point for threads t1, t2, and t3, to terminate before running the final part of the code (which is a cleanup routine).

So, reading a bit, seems like I need thread.join to do this and you can see that in my code below. However, when i ran it, t1.join or t2.join or t3.join never actually completes. It waits for an indeterminate amount of time. So, reading a bit further I think the reason for this is the thread is not terminating. MySub has an end... so I don't know why this would be?

Any ideas why thread.join is not completing?
Dim alParam As New ArrayList
      Dim paramTS As New ParameterizedThreadStart(AddressOf mySub)
      Dim t1 As Thread = Nothing
      Dim t2 As Thread = Nothing
      Dim t3 As Thread = Nothing

      'Create parameter array for the thread
      Dim d1 As New SelectSheet(glWorksheets)
      d1.lblSelectDHLSheet.Text = "Please select the r189 for customer 41335."
      d1.ShowDialog()
      alParam.Add(d1.lstSelectSheet.SelectedItem.ToString())
      alParam.Add(True) 'for blnRateAll
      alParam.Add(True) 'for blnFirstPass
      alParam.Add(False) 'for blnSecondPass
      alParam.Add(False) 'for blnFinalPass
      d1.Dispose()

      t1 = New Thread(paramTS)
      t1.Start(alParam)

      Dim d2 As New SelectSheet(glWorksheets)
      d2.lblSelectDHLSheet.Text = "Please select the r189 for customer 25933."
      d2.ShowDialog()
      alParam(0) = d2.lstSelectSheet.SelectedItem.ToString()
      alParam(2) = False 'for blnFirstPass
      alParam(3) = True 'for blnSecondPass

      t2 = New Thread(paramTS)
      t2.Start(alParam)

      Dim d3 As New SelectSheet(glWorksheets)
      d3.lblSelectDHLSheet.Text = "Please select the r189 for customer 10929."
      d3.ShowDialog()
      alParam(0) = d3.lstSelectSheet.SelectedItem.ToString()
      alParam(3) = False 'for blnSecondPass
      alParam(4) = True 'for blnFinalPass

      t3 = New Thread(paramTS)
      t3.Start(alParam)

      'make threads wait before we cleanup the references
      Dim blnT1 As Boolean = t1.Join(50000)
      Dim blnT2 As Boolean = t2.Join(50000)
      Dim blnT3 As Boolean = t3.Join(50000)

Open in new window

Any ideas why thread.join is not completing?
Without seeing the complete code, that is going to be difficult to diagnose.

You might find it easier to work with the ThreadPool than to manage the creation of threads yourself.
Avatar of AidenA

ASKER

yeah, but need to learn how to use threads... once I have a decent understanding I'll probably just simplify it and use threadpool or just a background worker thread for the UI or however you're supposed to do it.

But I just want to figure out why thread.join isn't working first. It actually works ok if I make mySub a simple subroutine which doens't really do anything. All threads join correctly. So the problem is in mySub which is a subroutine which automates excel... so it is working on excel objects. I noticed that t1 and t2 joined ok if I moved the opening of an excel file into the main thread (i.e. the code  wb = xlApp.Workbooks.Open("myexceldoc.xls") is moved out of mySub and called before creating the threads).

So again, not sure what was causing that error, but that solved it... I think. But not sure why t3 which is also calling mySub and is performing more or less the same actions as far as I can tell, is not joining.

I mean, how do I even go about trying to see where the error is? Is there a way of seeing exactly where the thread t3 is? What I can see right now is that it doesn't join... but I don't know where exactly it currently is? How do I debug this issue?

Thanks
Avatar of AidenA

ASKER

well surprisingly I tracked down the error actually... was able to just wait until t1 and t2 would have definitely finished and then debug so I could be sure I was on t3...

Error is coming from

SetProgress_ThreadSafe(Me.lblStatusLabel, "Closing Files", ProgressBar1, ProgressBar1.Value + 1)

which is the code I was using to avoid the GUI error in the beginning. There is the delegate at the beginning;

Delegate Sub SetProgress(ByVal lbl As Label, ByVal txt As String, ByVal pgb As ProgressBar, ByVal intProgress As Integer)

and the sub itself

Private Sub SetProgress_ThreadSafe(ByVal lbl As Label, ByVal txt As String, ByVal pgb As ProgressBar, ByVal intProgress As Integer)
      ' InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
      ' If these threads are different, it returns true.
      If lbl.InvokeRequired Then
         Dim MyDelegate As New SetProgress(AddressOf SetProgress_ThreadSafe)
         Me.Invoke(MyDelegate, New Object() {lbl, txt, pgb, intProgress})
      Else
         lbl.Text = txt
         pgb.Value = intProgress
      End If

... and on t3 it seemed to fail on the line Me.Invoke(MyDelegate, New Object() {lbl, txt, pgb, intProgress})

So, that code works fine with t1 and t2... does that info help you identify what the error could be?

ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of AidenA

ASKER

yep that did it. thanks for the info!

Aiden