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

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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











Sample Code You Can Use Using a Background Thread to Accomplish a Single Task


The code in Listing 9.1 is a class that enables you to manage the execution of a task on a background thread. It uses a state machine to keep track of its progress in getting set up, starting a new thread, running code on the thread, and exiting the thread when finished.

The sample also offers the ability for the main thread to request that the background operation be aborted. Calling the m_tHReadExecute. setProcessingState(ThreadExecuteTask.ProcessingState. requestAbort) method from another thread signals to the background processing thread that a request to abort has been made of it. It is up to the code running on the background processing thread to periodically check for this state and to abort if possible. The state machine for ThreadExecuteTask is shown in Figure 9.1.

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



using 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
}
ProcessingState m_processingState;
public delegate void
ExecuteMeOnAnotherThread(ThreadExecuteTask checkForAborts);
private ExecuteMeOnAnotherThread m_CallFunction;
private object m_useForStateMachineLock;
public ThreadExecuteTask
(ExecuteMeOnAnotherThread functionToCall)
{
//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()
//------------------------------------------------------
System.Threading.ThreadStart threadStart;
threadStart =
new System.Threading.ThreadStart(ThreadStartPoint);
System.Threading.Thread newThread;
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
}
//-------------------------------------------------------
//This function is the entry point that is called on the
//new thread
//-------------------------------------------------------
private void 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(this);
//If we didn't abort, change the execution state to indicate
//success
if(m_processingState != ProcessingState.aborted)
{
//Mark our execution as done
setProcessingState(ProcessingState.done);
}
//Exit the thread...
}
//--------------------------------------------------
//The state machine.
//--------------------------------------------------
public void setProcessingState(ProcessingState nextState)
{
//We should only allow one thread of execution to try
//to modify the state at any given time.
lock(m_useForStateMachineLock)
{
//If we are entering the state we are already in,
//do nothing.
if (m_processingState == nextState)
{
return;
}
//--------------------------------------------------
//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)
|| (m_processingState == ProcessingState.done))
{
return;
}
//Make sure the state transition is valid
switch(nextState)
{
case ProcessingState.notYetStarted:
throw new Exception
("Cannot enter 'notYetStarted' state");
case ProcessingState.waitingToStartAsync:
if(m_processingState != ProcessingState.notYetStarted)
{throw new Exception("Invalid state transition");}
break;
case ProcessingState.running:
if(m_processingState !=
ProcessingState.waitingToStartAsync)
{throw new Exception("Invalid state transition");}
break;
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) &&
(m_processingState != ProcessingState.requestAbort)
)
{throw new Exception("Invalid state transition");}
break;
case ProcessingState.aborted:
if(m_processingState != ProcessingState.requestAbort)
{throw new Exception("Invalid state transition");}
break;
}
//Allow the state change
m_processingState = nextState;
}
}
public ProcessingState State
{
get
{
ProcessingState currentState;
//Prevents simultaneous read/write of state
lock(m_useForStateMachineLock)
{
currentState = m_processingState;
}
return currentState;
}
}
} // End class

Figure 9.1. State machine for single task executing on a background thread.

[View full size image]

Listing 9.2 shows simulated work that can be done in a background thread. A message box is shown when the code starts to run on a background thread. Simulating the work is a series of one-third-second delays in between which the worker code checks to see whether another thread has requested it to abort its processing.

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



using System;
//---------------------------------------------------------
//Test code we will use to try background thread execution
//---------------------------------------------------------
public class Test1
{
public int m_loopX;
//------------------------------------------------------------
//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 void ThreadEntryPoint(ThreadExecuteTask threadExecute)
{
//This message box will be shown in the context of the thread
//it is running in
System.Windows.Forms.MessageBox.Show("In TEST");
//------------------------------
//60 times
//------------------------------
for (m_loopX = 0; m_loopX < 60; m_loopX++)
{
//If an abort has been requested, we should quit
if(threadExecute.State ==
ThreadExecuteTask.ProcessingState.requestAbort)
{
threadExecute.setProcessingState(
ThreadExecuteTask.ProcessingState.aborted);
return;
}
//Simulate work: Wait 1/3 second
System.Threading.Thread.Sleep(333);
}
}
} //End Class

Listing 9.3 contains code that can be run from the main user interface thread to initiate and control background processing. This code snippet is not a standalone class and should be placed inside a form and have the button click events hooked up to buttons on the form.

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



//The class that will manage our new thread's execution
private ThreadExecuteTask m_threadExecute;
//The class with the method we want to run async
Test1 m_testMe;
//-------------------------------------------------------
//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 void buttonStartAsyncExecution_Click(
object sender, System.EventArgs e)
{
//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
ThreadExecuteTask.ExecuteMeOnAnotherThread delegateCallCode;
delegateCallCode =
new ThreadExecuteTask.ExecuteMeOnAnotherThread(
m_testMe.ThreadEntryPoint);
//Tell the thread to get going!
m_threadExecute = new ThreadExecuteTask(delegateCallCode);
}
//Check the status of our execution
private void buttonCheckStatus_Click(object sender,
System.EventArgs e)
{
//Ask the thread management class what state it's in
System.Windows.Forms.MessageBox.Show(
m_threadExecute.State.ToString());
//Ask the class with the method running on the thread how it's progressing
System.Windows.Forms.MessageBox.Show(
m_testMe.m_loopX.ToString());
}
//Cause an illegal state transition (will raise an exception)
private void buttonCauseException_Click(object sender,
System.EventArgs e)
{
m_threadExecute.setProcessingState(
ThreadExecuteTask.ProcessingState.notYetStarted);
}
//Request the async code to abort its work
private void buttonAbort_Click(object sender, System.EventArgs e)
{
m_threadExecute.setProcessingState(
ThreadExecuteTask.ProcessingState.requestAbort);
}


/ 159