Title  Let a long process run asynchronously without multithreading 
Keywords  long process, multithreading, thread 
Categories  Software Engineering 


This example shows how to build a FibonacciLibrary DLL. This DLL contains a public class FibonacciCalculator that performs a long calculation: it calculates Fibonacci numbers recursively. (There are much faster methods for calculating Fibonacci numbers but this one makes an easy example. See my book ReadytoRun Visual Basic Algorithms for faster methods.)
The main program creates a FibonacciLibrary.CalculateFibonacci object and calls its public CalculateFibonacci subroutine to start the calculation. CalculateFibonacci stores a reference to the current CalculateFibonacci object in the variable g_FibonacciCalculator and saves its parameter in m_Parameter. It uses the SetTimer API function to create a timer that will wait for 1 millisecond and then returns. (You could use a hidden form with a Timer control on it instead of an API timer if you wanted.)


' Start calculating a Fibonacci number the slow,
' stupid way.
Public Sub CalculateFibonacci(ByVal i As Integer)
' Save a reference to ourself.
Set g_FibonacciCalculator = Me
' Save the parameter.
m_Parameter = i
' Start the timer.
g_TimerId = SetTimer(0, 0, 1, _
AddressOf FibonacciTimer)
' Return so the main program can do stuff.
End Sub


When the API timer fires, it calls the FibonacciTimer subroutine. This routine is in a BAS module within the FibonacciLibrary project. FibonacciTimer kills the timer so it doesn't execute again and then calls the saved FibonacciCalculator object's BeginFibonacciCalculation to begin the actual calculation.


' Start calculating the Fibonacci number.
Public Sub FibonacciTimer(hwnd As Long, msg As Long, _
idTimer As Long, dwTime As Long)
' Stop the timer.
KillTimer 0, g_TimerId
' Start the actual Fibonacci calculation.
g_FibonacciCalculator.BeginFibonacciCalculation
End Sub


BeginFibonacciCalculation calls the Fibonacci function to calculate the Fibonacci number. It then raises the FibonacciDone event to give the main program the result.


' Start calculating a Fibonacci number the slow,
' stupid way.
Friend Sub BeginFibonacciCalculation()
Dim result As Double
' Perform the calculation.
m_Iterations = 0
result = Fibonacci(m_Parameter)
' Return the result.
RaiseEvent FibonacciDone(result)
End Sub
' Recursively calculate the Fibonacci number.
Private Function Fibonacci(ByVal i As Double) As Double
' Every now and then, give the main program
' a chance to do something.
m_Iterations = m_Iterations + 1
If m_Iterations Mod 100 = 0 Then DoEvents
' Calculate the Fibonacci number.
If i <= 1 Then
Fibonacci = 1
Else
Fibonacci = Fibonacci(i  1) + Fibonacci(i  2)
End If
End Function


The following code shows how the main program works. When the user clicks the Calculate button, its event handler clears any previous results, enables the Timer tmrWaiting, and invokes the FibonacciCalculator's CalculateFibonacci method.
When the tmrWaiting Timer fires, the program displays the number of ellapsed seconds.
When the FibonacciCalculator finishes, the FibonacciDone event handler displays the result and disables tmrWaiting.


Private WithEvents m_Calculator As _
FibonacciLibrary.FibonacciCalculator
Private m_StartTime As Single
Private Sub cmdCalculate_Click()
' Clear the previous results.
lblResult.Caption = ""
lblTime.Caption = ""
tmrWaiting.Enabled = True
m_StartTime = Timer
DoEvents
' Start calculating the Fibonacci number.
m_Calculator.CalculateFibonacci CInt(txtNumber.Text)
End Sub
Private Sub tmrWaiting_Timer()
lblTime.Caption = CInt(Timer  m_StartTime)
End Sub
Private Sub m_Calculator_FibonacciDone(ByVal result As _
Double)
' Display the result.
lblResult.Caption = result
tmrWaiting.Enabled = False
End Sub


This example doesn't really provide much feedback. The main program simply displays the ellapsed time since the Fibonacci calculation started. Increasing the number by 1 roughly doubles the execution time to start with small values (25 or so) and slowly increase them until you see how the program runs on your computer.
Another method for providing feedback would be to give the FibonacciCalculator a public status routine so the main program could periodically ask it how far the calculation had gone. Perhaps a better technique would be to make the FibonacciCalculator periodically raise status events telling the main program how far it had gone in its calculation.



