Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] - نسخه متنی

Ivo Salmre

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید













Chapter 9 (Performance and Multithreading) Samples

Listing 9.1. Code to Manage Single-Task Execution on a Background Thread




Option Strict On
Imports System
Public Class ThreadExecuteTask
'States we can be in.
Public Enum ProcessingState
'----------------
'Initial state
'----------------
'Not doing anything interesting yet
notYetStarted
'----------------
'Working states
'----------------
'We are waiting for the background thread to start
waitingToStartAsync
'Code is running in the background thread
running
'Requesting that the calculation be aborted
requestAbort
'----------------
'Final states
'----------------
'Final State: We have successfully completed background
'execution
done
'Final State: We have aborted the background execution
'before finishing
aborted
End Enum
Private m_processingState As ProcessingState
Public Delegate Sub ExecuteMeOnAnotherThread(ByVal _
checkForAborts As ThreadExecuteTask)
Private m_CallFunction As ExecuteMeOnAnotherThread
Private m_useForStateMachineLock As Object
Public Sub New(ByVal functionToCall As ExecuteMeOnAnotherThread)
'Create an object we can use for a lock for the
'state machine transition function
m_useForStateMachineLock = New Object
'Mark our execution as ready to start
m_processingState = ProcessingState.notYetStarted
'Store the function we are supposed to call on the new
'thread
m_CallFunction = functionToCall
'------------------------------------------------------
'Create a new thread and have it start executing on:
' this.ThreadStartPoint()
'------------------------------------------------------
Dim threadStart As System.Threading.ThreadStart
threadStart = _
New System.Threading.ThreadStart(AddressOf ThreadStartPoint)
Dim newThread As System.Threading.Thread
newThread = New System.Threading.Thread(threadStart)
'Mark our execution as ready to start (for determinism,
'it is important to do this before we start the thread!)
setProcessingState(ProcessingState.waitingToStartAsync)
'Tell the OS to start our new thread async.
newThread.Start()
'Return control to the caller on this thread
End Sub
'-------------------------------------------------------
'This function is the entry point that is called on the
'new thread
'-------------------------------------------------------
Private Sub ThreadStartPoint()
'Set the processing state to indicate we are running on
'a new thread!
setProcessingState(ProcessingState.running)
'Run the user's code, and pass in a pointer to our class
'so that code can occasionally call to see if an abort has
'been requested
m_CallFunction(Me)
'If we didn't abort, change the execution state to indicate
'success
If (m_processingState <> ProcessingState.aborted) Then
'Mark our execution as done
setProcessingState(ProcessingState.done)
End If
'Exit the thread...
End Sub
'--------------------------------------------------
'The state machine.
'--------------------------------------------------
Public Sub setProcessingState(ByVal nextState As _
ProcessingState)
'We should only allow one thread of execution to try
'to modify the state at any given time.
SyncLock (m_useForStateMachineLock)
'If we are entering the state we are already in,
'do nothing.
If (m_processingState = nextState) Then
Return
End If
'--------------------------------------------------
'Some very simple protective code to make sure
'we can't enter another state if we have either
'successfully finished, or successfully aborted
'--------------------------------------------------
If ((m_processingState = ProcessingState.aborted) _
OrElse (m_processingState = ProcessingState.done)) Then
Return
End If
'Make sure the state transition if valid
Select Case (nextState)
Case ProcessingState.notYetStarted
Throw New Exception _
("Cannot enter 'notYetStarted' state")
Case ProcessingState.waitingToStartAsync
If (m_processingState <> ProcessingState.notYetStarted) _
Then
Throw New Exception("Invalid state transition")
End If
Case ProcessingState.running
If (m_processingState <> _
ProcessingState.waitingToStartAsync) Then
Throw New Exception("Invalid state transition")
End If
Case ProcessingState.done
'We can complete work only if we have been running.
'It is also possible that the user requested an
'abort, but we finished the work before aborting
If ((m_processingState <> ProcessingState.running) _
AndAlso _
(m_processingState <> ProcessingState.requestAbort)) Then
Throw New Exception("Invalid state transition")
End If
Case ProcessingState.aborted
If (m_processingState <> _
ProcessingState.requestAbort) Then
Throw New Exception("Invalid state transition")
End If
End Select
'Allow the state change
m_processingState = nextState
End SyncLock
End Sub
Public ReadOnly Property State() As ProcessingState
Get
Dim currentState As ProcessingState
'Prevents simultanious read/write of the state variable
SyncLock (m_useForStateMachineLock)
currentState = m_processingState
End SyncLock
Return currentState
End Get
End Property
End Class


Listing 9.2. Test Example for Work to Be Done on a Background Thread




Option Strict On
Imports System
'---------------------------------------------------------
'Test code we will use to try background thread execution
'---------------------------------------------------------
Public Class Test1
Public m_loopX As Integer
'------------------------------------------------------------
'The function that gets called on a background thread
'
' [in] threadExecute: The class managing our thread's
' execution. We can check this to see if
' we should abort our calculation.
'---------------------------------------------------------------
Public Sub ThreadEntryPoint(ByVal threadExecute As _
ThreadExecuteTask)
'This message box will be shown in the context of the thread
'it is running in
MsgBox("In TEST")
'------------------------------
'60 times
'------------------------------
For m_loopX = 1 To 60
'If an abort has been requested, we should quit
If (threadExecute.State = _
ThreadExecuteTask.ProcessingState.requestAbort) Then
threadExecute.setProcessingState( _
ThreadExecuteTask.ProcessingState.aborted)
Return
End If
'Simulate work: Wait 1/3 second
System.Threading.Thread.Sleep(333)
Next
End Sub
End Class


Listing 9.3. Code to Test and Run the Sample Code Above



[View full width]



'The class that will manage our new thread's execution
Private m_threadExecute As ThreadExecuteTask
'The class with the method we want to run async
Private m_testMe As Test1
'-------------------------------------------------------
'This code needs to be run before the other code because
'it starts the background execution!
'
'Create a new thread and get the execution going
'-------------------------------------------------------
Private Sub buttonStartAsyncExecution_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles buttonStartAsyncExecution.Click
'Create an instance of the class we
'want to call a method on, in another thread
m_testMe = New Test1
'Package the class' method entry point up in a delegate
Dim delegateCallCode As _
ThreadExecuteTask.ExecuteMeOnAnotherThread
delegateCallCode = _
New ThreadExecuteTask.ExecuteMeOnAnotherThread(AddressOf _
m_testMe.ThreadEntryPoint)
'Tell the thread to get going!
m_threadExecute = New ThreadExecuteTask(delegateCallCode)
End Sub
'Cause an illegal state transition (will raise an exception)
Private Sub buttonCauseException_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles buttonCauseException.Click
m_threadExecute.setProcessingState( _
ThreadExecuteTask.ProcessingState.notYetStarted)
End Sub
'Request the async code to abort its work
Private Sub buttonAbort_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles buttonAbort.Click
m_threadExecute.setProcessingState( _
ThreadExecuteTask.ProcessingState.requestAbort)
End Sub
'Check the status of our execution
Private Sub buttonCheckStatus_Click(ByVal sender As System.Object
_ ByVal e As System
.EventArgs) Handles
ButtonCheckStatus.Click
'Ask the thread management class what state it's in
MsgBox(m_threadExecute.State.ToString())
'Ask the class with the method running on the thread how it's progressing
MsgBox(m_testMe.m_loopX.ToString())
End Sub


Listing 9.4. Code That Goes into the Smartphone Form1.cs Class




'----------------------------------------------------
'All this code belongs inside a Form1.cs class
'----------------------------------------------------
'The object that will do our background calculation
Private m_findNextPrimeNumber As FindNextPrimeNumber
'---------------------------------------------------------
'Update the status text...
'---------------------------------------------------------
Sub setCalculationStatusText(ByVal text As String)
Label1.Text = text
End Sub
Private Sub menuItemExit_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles menuItemExit.Click
Me.Close()
End Sub
'---------------------------------------------------------
'Menu item for starting the background calculation
'---------------------------------------------------------
Private Sub menuItemStart_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles menuItemStart.Click
'What number do we want to start looking at
Dim startNumber As Long = _
System.Convert.ToInt64(TextBox1.Text)
'Set up the background calculation
m_findNextPrimeNumber = New FindNextPrimeNumber(startNumber)
'Start the background processing running...
m_findNextPrimeNumber.findNextHighestPrime_Async()
'Set up the timer that will track the calculation
Timer1.Interval = 400 '400 ms
Timer1.Enabled = True
End Sub
'---------------------------------------------------------
'Menu item for "Aborting" a calculation under progress
'---------------------------------------------------------
Private Sub menuItemAbort_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles menuItemAbort.Click
'If we are not doing a calculation, do nothing.
If (m_findNextPrimeNumber Is Nothing) Then Return
'Set the thread up to abort
m_findNextPrimeNumber.setProcessingState( _
FindNextPrimeNumber.ProcessingState.requestAbort)
'Let the user instantly know we are getting
'ready to abort...
setCalculationStatusText("Waiting to abort..")
End Sub
'-------------------------------------------------------
'This timer gets called on the UI thread and enables
'us to keep track of progress on our background
'calculation
'-------------------------------------------------------
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
'If we get called and we have no prime number
'we are looking for, turn off the timer
If (m_findNextPrimeNumber Is Nothing) Then
Timer1.Enabled = False
Return
End If
'--------------------------------------------
'If we've been aborted, throw out the prime seeker
'and turn off the timer
'--------------------------------------------
If (m_findNextPrimeNumber.getProcessingState = _
FindNextPrimeNumber.ProcessingState.aborted) Then
Timer1.Enabled = False
m_findNextPrimeNumber = Nothing
setCalculationStatusText("Prime search aborted")
Return
End If
'--------------------------------------------
'Did we find the right answer?
'--------------------------------------------
If (m_findNextPrimeNumber.getProcessingState = _
FindNextPrimeNumber.ProcessingState.foundPrime) Then
Timer1.Enabled = False
'Show the result
setCalculationStatusText("Found! Next Prime = " + _
m_findNextPrimeNumber.getPrime().ToString())
m_findNextPrimeNumber = Nothing
Return
End If
'--------------------------------------------
'The calculation is progressing. Give the
'user an idea of the progress being made...
'--------------------------------------------
'Get the two output values
Dim numberCalculationsToFar As Long
Dim currentItem As Long
m_findNextPrimeNumber.getExecutionProgressInfo( _
numberCalculationsToFar, currentItem)
setCalculationStatusText("In progress. Looking at: " + _
CStr(currentItem) + ". " + _
CStr(numberCalculationsToFar) + _
" calculations done for you so far!")
End Sub


Listing 9.5. Code for the FindNextPrimeNumber.cs Class




Option Strict On
Imports System
Public Class FindNextPrimeNumber
'States we can be in.
Public Enum ProcessingState
notYetStarted
waitingToStartAsync
lookingForPrime
foundPrime
requestAbort
aborted
End Enum
Private m_startPoint As Long
Private m_NextHighestPrime As Long
'How many items have been searched?
Private m_comparisonsSoFar As Long
'What is the current item we are doing a prime search for?
Private m_CurrentNumberBeingExamined As Long
'Called to get an update on how the calculation is progressing
Public Sub getExecutionProgressInfo( _
ByRef numberCalculationsSoFar As Long, _
ByRef currentItemBeingLookedAt As Long)
'NOTE: We import this thread lock to make sure that
'we are not reading these values while they are in the
'middle of being written out. Because 'm_comparisonsSoFar'
'and 'm_CurrentNumberBeingExamined' may be
'accessed from multiple threads, any read or write
'operation to them needs to be synchronized with "lock" to
'ensure that reads and writes are atomic.
SyncLock (Me)
numberCalculationsSoFar = m_comparisonsSoFar
currentItemBeingLookedAt = m_CurrentNumberBeingExamined
End SyncLock
End Sub
Private m_processingState As ProcessingState
'--------------------------------------------------
'A very simple state machine.
'--------------------------------------------------
Public Sub setProcessingState(ByVal nextState As _
ProcessingState)
'--------------------------------------------------
'Some very simple protective code to make sure
'we can't enter another state if we have either
'successfully finished, or successfully aborted
'--------------------------------------------------
If ((m_processingState = ProcessingState.aborted) _
OrElse (m_processingState = ProcessingState.foundPrime)) _
Then
Return
End If
'Allow the state change
m_processingState = nextState
End Sub
Public ReadOnly Property getProcessingState() As ProcessingState
Get
Return m_processingState
End Get
End Property
'---------------------------------------------------
'Returns the prime
'---------------------------------------------------
Public Function getPrime() As Long
If (m_processingState <> ProcessingState.foundPrime) Then
Throw New Exception("Prime number not calculated yet!")
End If
Return m_NextHighestPrime
End Function
'Class constructor
Public Sub New(ByVal startPoint As Long)
setProcessingState(ProcessingState.notYetStarted)
m_startPoint = startPoint
End Sub
'------------------------------------------------------------
'Creates a new worker thread that will call
' "findNextHighestPrime()"
'------------------------------------------------------------
Public Sub findNextHighestPrime_Async()
Dim threadStart As System.Threading.ThreadStart
threadStart = _
New System.Threading.ThreadStart(AddressOf _
findNextHighestPrime)
Dim newThread As System.Threading.Thread
newThread = New System.Threading.Thread(threadStart)
'Set our processing state to say that we are looking
setProcessingState(ProcessingState.waitingToStartAsync)
newThread.Start()
End Sub
'------------------------------------------------------------
'This is the main worker-function. This synchronously starts
'looking for the next prime number and does not exit until
'either:
' (a) The next prime is found
' (b) An external thread to this thread tells us to abort
'------------------------------------------------------------
Public Sub findNextHighestPrime()
'If we've been told to abort, don't even start looking
If (m_processingState = ProcessingState.requestAbort) Then
GoTo finished_looking
End If
'Set our processing state to say that we are looking
setProcessingState(ProcessingState.lookingForPrime)
Dim currentItem As Long
'See if it's odd
If ((m_startPoint And 1) = 1) Then
'It's odd, start at the next odd number
currentItem = m_startPoint + 2
Else
'It's even, start at the next odd number
currentItem = m_startPoint + 1
End If
'Look for the prime item.
While (m_processingState = ProcessingState.lookingForPrime)
'If we found the prime item, return it
If (isItemPrime(currentItem) = True) Then
m_NextHighestPrime = currentItem
'Update our state
setProcessingState(ProcessingState.foundPrime)
End If
currentItem = currentItem + 2
End While
finished_looking:
'Exit. At this point we have either been
'Told to abort the search by another thread, or
'we have found and recorded the next highest prime number
'If an abort was requested, note that we have aborted
'the process.
If (m_processingState = ProcessingState.requestAbort) Then
setProcessingState(ProcessingState.aborted)
End If
End Sub
'Helper function that looks to see if a specific item
'is a prime number.
Private Function isItemPrime(ByVal potentialPrime _
As Long) As Boolean
'If it's even, it's not prime
If ((potentialPrime And 1) = 0) Then
Return False
End If
'We want to look up until just past the square root
'of the item
Dim end_point_of_search As Long
end_point_of_search = _
CLng(System.Math.Sqrt(potentialPrime)) + 1
Dim current_test_item As Long = 3
While (current_test_item <= end_point_of_search)
'---------------------------------
'Check to make sure we have not been asked to abort!
'---------------------------------
If (m_processingState <> ProcessingState.lookingForPrime) _
Then
Return False
End If
'If the item is divisible without remainder,
'it is not prime
If (potentialPrime Mod current_test_item = 0) Then
Return False
End If
'advance by two
current_test_item = current_test_item + 2
'------------------------------------------------------
'Up the count of items we have examined
'------------------------------------------------------
'NOTE: We import this thread lock to make sure that
'we are not reading these values while they are in the
'middle of being written out. Because 'm_comparisonsSoFar'
'and 'm_CurrentNumberBeingExamined' may be
'accessed from multiple threads, any read or write
'operation to them needs to be synchronized with "lock" to
'ensure that reads and writes are atomic.
SyncLock (Me)
m_CurrentNumberBeingExamined = potentialPrime
m_comparisonsSoFar = m_comparisonsSoFar + 1
End SyncLock
End While
'The item is prime
Return True
End Function
End Class



/ 159