To Do: Compare to Java

 

Multithreading is accomplished by using a combination of classes Thread and Monitor.

 

Thread States and Transitions

 

State

 

Unstarted

Thread created but not started. The class.method is the ThreadStart delegate – the method to execute when the thread enters the Start state. Note that the method must not take any arguments.

 

Dim myThread as New Thread(Address of class.method)

 

Started

Thread put in start state by calling start.  myThread.Start()

 

But the thread may not start executing immediately. It will start when it comes to top of priority queue and is allocated a timeslice (quantum) on the CPU

 

As the program executes it can be placed back into the Started state by a number of different actions

Running

The thread as been ‘dispatched’ to the cpu for execution and is executing. On first execution the thread executes the ThreadStart delegate passed to it

 

The thread will remain in the Running state until it’s timeslice is up or it is moved to a different state by other actions.

 

WaitSleepJoin

A Running thread can enter the WaitSleepJoin state in 3 ways. The ‘WaitSleepJoin’ state basically represents the combination of 3 different States, but they all result in the thread suspended for something else to happen. The thread can be put in this State in a a) Wait state, b) Sleep state, or c) Join state

 

The 3 different events that can occur to put the Thread in the WaitSleepJoin state are:

  1. The program can’t continue until some condition is satisfied (eg. a queue is empty and the program needs to wait until some other process places something on the queue).

 

The program can call the Monitor.Wait() method.

 

The thread stays in the WaitSleepJoin state until another thread(process) calls Monitor.pulse() or Monitor.PulseAll.

 

Monitor.Pulse() moves the next waiting thread to the Started state.

 

Monitor.PulseAll() moves all waiting threads to the Started state.

 

  1. The running thread can call Thread.Sleep(numberMilliseconds)
  2. The thread needs to wait for some other thread(process) to finish executing. The thread calls the other threads join() method. The thread stays in the WaitSleepJoin state until the other thread terminates. It then returns to the Started state 

 

Suspended

A thread in the Running state can be put in the Suspended state when the thread.Suspend() method is called. The thread can be moved back to the Started state when the thread.Resume() method is called.

 

Stopped

The thread enters the Stopped state when the ThreadStart delegate terminates. This can come about through ‘normal’ execution or the thread can be forced to that state by either the program calling the Thread.Abort() method or some external process that has a handle on the Thread calls the abort method

 

Garbage collection only takes place when the thread is in the stopped state and there are no references to the thread object

Blocked

A Running thread is moved to the Blocked state when a program issues an I/O request. The thread remains in the Blocked state until the I/O request is satisfied. The thread is then placed back to the Started state.

 

Threads can also enter the Blocked state when another thread has acquired exclusive use on a data object (via Monitor.Enter()_

 

 

Thread Priorities

 

Threads can be assigned one of the following 5 priorities

           

            ThreadPriority.Lowest

            ThreadPriority.BelowNormal

            ThreadPriority.Normal  (default)

            ThreadPriority.AboveNormal

            ThreadPriority.Highest

 

The values are from Namspace System.Threading

 

 

Thread and Data Synchronization

 

Where program data needs to be manipulated by more that 1 thread, class Monitor can be used to synchronize access to the data.

 

A program needing exclusive access to an object, the Monitor.Enter() method is used to gain a lock on the data object.

 

Each object contains a SyncBlock that maintains the state of the object’s lock. Monitor methods use the data in the SyncBlock to determine the state of the lock on the object.

 

Once an object is locked, all other threads accessing the object are put in the Blocked state until the object is unlocked.

 

The program gives up exclusive access by executing Monitor.Exit() on the data object. The Exit() method updates the SyncBlock status. Any threads that were placed in Blocked status waiting for the object can be set to the Started state.

 

Another way of obtaining a lock on an object is via the keyword SyncLock

 

            SyncLock (objectToLock)

                        ‘ put in code that manipulates the objectToLock

            End SyncLock

 

When the SyncLock block ends for any reason (normal execution, thrown exception, …) the lock is automatically released on objectToLock.

 

The objectToLock is the same object reference that would normally be passed to Montir.Enter(), Exit(), Pulse(), and PulseAll().  Oftentimes the objectToLock is ‘Me’.

 

 

 

Thread Methods

 

Get the thread executing the program

Imports System.Threading

…

   Dim myThread as Thread = Thread.CurrentThread

   ‘ note that you have access to Thread methods same as any other class

 

Put yourself to sleep

...

‘ sleep between 0 and 10 secs

    myThread.Sleep(randomObject.Next(10001) 

 

Starting a object method on a separate thread

Imports System.Threading

…

   ‘ create instance like any other

 

   Dim separateThreadObject as New  MyObject() 

  

  ‘ create a thread and give it address of method to start execution on

  Dim separateThread as New Thread(AddressOf 

separateThreadObject.someMethod) 

 

  ‘ add start the thread (actually just puts thread in start state )

  separateThread.Start()

 

 

 

 

 

 

Objects requiring synchronization

 

In general when object that requires synchronization is separate from the objects that manipulate it. The object contains set and get methods that contain calls to Monitor methods that to allow the data synchronization to occur. An object template for an object with synchronization is below.

 

Note that if an exception occurs after the Monitor.Enter() method is called, make sure to call Monitor.Exit() to release the lock. So it is a good idea to use Try/Catch/Finally and put the Monitor.Exit() call in the Finally block to ensure any locks are released.

 

 

Imports System.Threading

 

Public Class ObjectWithSynchronziation

    Private  …       ‘ data to be synchronized

 

Public Property SomeProperty() as Integer   ‘ Or string or ….

       Get

            Try 

                        Monitor.Enter(Me)          ‘ get a lock, if another process has lock you will Blocked

                        If   …. Then                   ‘ Even if can continue, if data not available, go to a           

                                                            ‘  Blocked state

                                    Monitor.Wait(Me)

                        End If

                        ‘ when here you have the lock and data is available.

                        ‘ do whatever you need to do

                        …

            Catch anyExceptions as …

                        …

            Finally

                        ‘ tell any waiting threads your are done (but you still have lock on object)

                        Monitor.Pulse(Me)

                        ‘ You may want to make a copy of the data so you won’t have to worry about it

                        ‘being overlaid if objects Started from Pulse above immediately execute on this

                        ‘object

                        Dim valueToReturn as Integer = valueToReturnFromAbove

                        ‘ Now unlock the object

                        Monitor.exit(Me)

            End Try

            ‘ And return the value

            Return valueToReturn

    End Get

 

    Set(ByVal integervalue as Integer)

            Try

                        ‘ lock the object (or go into Blocked state if some other process has it locked)

                        Monitor.Enter(Me)

                        ‘Check to make sure the object is in a state that you can change, if not go into

                        ‘ a WaitSleepJoin state

                        If … Then

                                    Monitor.Wait(Me)

                        End If

                        ‘ You are here when you are good to go. Do your thing

                        …

            Catch anyExceptions as …

                        …

            Finally

                        ‘ Tell any waiting threads to wake up

                        Monitor.Pulse(Me)

                        ‘ And release the lock

                        Monitor.Exit(Me)

            End Try

    End Set

 

End Property

 

End Class        

 

The advantage of a lock obtained via a SyncLock is that the lock is released if an exception occurs so no special exception coding is needed.

 

Imports System.Threading

 

Public Class ObjectWithSynchronziation

    Private  …       ‘ data to be synchronized

 

Public Property SomeProperty() as Integer   ‘ Or string or ….

       Get

            SyncLock(Me)   ‘ get a lock, if another process has lock you will Blocked

                        If   …. Then                   ‘ Even if can continue, if data not available, go to a           

                                                            ‘  Blocked state

                                    Monitor.Wait(Me)

                        End If

                        ‘ when here you have the lock and data is available.

                        ‘ do whatever you need to do

                        …

                        ‘ tell any waiting threads your are done (but you still have lock on object)

                        Monitor.Pulse(Me)

                        ‘ And return the value – note still w/in SyncLock

                        Return valueToReturn

            End SyncLock   ‘ since above Return exited block Synclock automatically released

    End Get

 

    Set(ByVal integervalue as Integer)

            SyncLock(Me)

                        ‘Check to make sure the object is in a state that you can change, if not go into

                        ‘ a WaitSleepJoin state

                        If … Then

                                    Monitor.Wait(Me)

                        End If

                        ‘ You are here when you are good to go. Do your thing

                        …

                        Monitor.Pulse(Me)

            End Synclock

    End Set

 

End Property

 

End Class