Passing Parameters to Threads

It is very common to have methods or procedures that accept parameters. Recall from previous discussions, however, that the procedure that is passed to the thread when it is created cannot have a return value and cannot accept parameters. This complicates your work because you have to find some way to get data into the procedure without using the standard method of passing parameters on the procedure call.

Just as with returning a value, there are two ways to pass parameters to procedures running on other threads: You can use module or global variables, or you can use properties or fields. There are plusses and minuses with each approach, of course. You'll examine both methods now, but understand that your current example using the Orders Web service doesn't really lend itself to accepting parameters, because the GetOrders method does not accept any parameters. Rather than recoding the Orders Web service, you'll just create a new procedure and class to handle parameters.

Passing Parameters with Global Variables

To see how to pass parameters using global variables, you'll need to create a new procedure inside of your Form1 class. This procedure will mimic the example you saw in Chapter 3, but you'll do more with it as far as passing parameters.

First, add two controls to your form. Add a button and name it cmdPassParam. Add a text box and name it txtCounter. Clear out the Text property of txtCounter, and change the Text property of cmdPassParam to Pass Params.

Now, add the following code to your form:

Dim mlCount As Long

Private Sub cmdPassParam_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdPassParam.Click
   mlCount = 100000
   Counter()
End Sub

Sub Counter()
   Dim lCount As Long
   For lCount = 1 To mlCount
      txtCounter.Text = lcount
   Next
End Sub

In this code, you create a module-level variable named mlCount, which is set to 100,000 in the cmdPassParam_Click sub. Feel free to adjust this number higher or lower depending on how long you want the thread to run.

In the Counter routine, you simply execute a loop the number of times set in the mlCount variable. The number is displayed in the txtCounter text box. If you run this project and click on the Pass Params button, you'll notice that if you then try to click on the Beep button, nothing happens because execution is blocked on the main thread as long as the loop in Counter is executing. You'll also notice that you don't see the number changing in the text box; that is because the control is not able to grab the necessary processor cycles to display the new value. This is what you saw in the example in Chapter 3.

In this example, you could have easily passed the value of mlCount into counter as a parameter. There's no need in this example for the module-level variable mlCount. However, you are about to multithread this example, and you won't be able to pass parameters after you run Counter on its own thread. Therefore, this example already has the value of the number of loop iterations set in a module-level variable.

Now, modify the code to use threads. Change the cmdPassParam_Click sub to look like this:

Private Sub cmdPassParam_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdPassParam.Click
   mlCount = 100000
   Dim threadCounter As New System.Threading.Thread(AddressOf Counter)
   threadCounter.Start()
End Sub

After making this change, you can run the code again. This time, the Beep button will respond to you while the Counter routine is running. In addition, you will see that the number in the txtCounter text box climbs as the loop executes. This means that you have successfully multithreaded your application, and from the Counter procedure, which is running on a new thread, you are able to pick up a value using the module-level variable approach.

What are the minuses with this approach? First, as discussed earlier in this chapter, some purists feel that global variables are inherently bad. Another, perhaps more important minus is that if you were to spawn multiple threads that all called Counter, they all would have to use the same value of mlCount. To get around this limitation, you will probably want to use the second approach, which is to use fields or properties of an object.

Passing Parameters with Fields or Properties

A more common approach to passing a parameter to another thread is to create a wrapper class, much like this chapter's earlier ServiceWrapper. You then create properties or fields (public variables) in the class and set those. You then call the method, but you place the method on its own thread before you execute it. This allows you to have multiple objects in memory, each with different values for the parameters, and you can run them all at the same time if you choose.

To see this, add a new class to your project and name it Counter.vb. Add the following code to the class:

Public Class Counter
   Public mlCount As Long

   Public Sub Count()
      Dim lCount As Long
      For lCount = 1 To mlCount
         'do nothing
      Next
      MsgBox("Thread done, mlCount was " & mlCount.ToString)
   End Sub
End Class

In the Counter class, you are creating a field named mlCount, and a method named Count. The Count method simply runs through a loop, but doesn't update a text box as you saw in the previous example. When it is done, it displays a message box saying that it is done, and how many times it ran through the loop.

Back in the form, modify the code for the cmdPassParam_Click sub to look like this:

Private Sub cmdPassParam_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdPassParam.Click
   Dim count1 As New Counter()
   Dim count2 As New Counter()
   count1.mlCount = 1000000000
   count2.mlCount = 99999999
   Dim threadCounter1 As New System.Threading.Thread(AddressOf count1.Count)
   Dim threadCounter2 As New System.Threading.Thread(AddressOf count2.Count)
   threadCounter1.Start()
   threadCounter2.Start()
End Sub

Now you are creating two instances of the Counter class, called count1 and count2. Each class gets a different value for the mlCount field, and you might want to modify these for your particular computer. You then spawn two threads, one for the Count method of each class. You then start both threads, so they are running simultaneously.

When the threads finish, they will display message boxes showing that they are done, and the number of times you executed the loop in that particular thread. This shows how you can pass parameters into an object before you start the thread, which gets you around the problem of not being able to pass parameters to procedures operating on a different thread.

If you look at Figure 11.3, you will see the two message boxes that appeared. These message boxes are from two instances of the same class, running on different threads, and having different values passed in, thanks to fields on the object.

Figure 11.3. Two message boxes from two instances of the same class, running on two different threads and containing different field values.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.242.62