Программирование мобильных устройств на платформе .NET Compact Framework - Иво Салмре
Шрифт:
Интервал:
Закладка:
currentItem.ToString() + ". " +
numberCalculationsToFar.ToString() +
" calculations done for you so far!");
// setCalculationStatusText("Вычисления продолжаются. Поиск в области: " +
// currentItem.ToString() + ". " +
// "Для вас выполнено " +
// numberCalculationsToFar.ToString() +
// " расчетов!");
}
Листинг 9.5. Код класса FindNextPrimeNumber.csusing System;
public class FindNextPrimeNumber {
//Перечисляем возможные состояния
public enum ProcessingState {
notYetStarted,
waitingToStartAsync,
lookingForPrime,
foundPrime,
requestAbort,
aborted
}
long m_startPoint;
long m_NextHighestPrime;
//Поиск какого количества элементов выполнен?
long m_comparisonsSoFar;
//Для какого элемента сейчас выполняется поиск простого числа?
long m_CurrentNumberBeingExamined;
//Вызывается для обновления информации о состоянии выполнения
public void getExecutionProgressInfo(out long numberCalculationsSoFar, out long currentItemBeingLookedAt) {
//ПРИМЕЧАНИЕ. Мы используем блокирование потока для уверенности в том,
//что эти значения не считываются во время выполнения операции
//их записи. Поскольку доступ к m_comparisonsSoFar
//и m_CurrentNumberBeingExamined могут осуществлять
//одновременно несколько потоков, любая выполняемая над ними
//операция записи/считывания должна синхронизироваться с "блокировкой",
//что будет гарантировать "атомарность" этих операций
lock (this) {
numberCalculationsSoFar = m_comparisonsSoFar;
currentItemBeingLookedAt = m_CurrentNumberBeingExamined;
}
}
ProcessingState m_processingState;
//---------------------------
//Простейший конечный автомат
//---------------------------
public void setProcessingState(ProcessingState nextState) {
//------------------------------------------------------
//Простейший защитный код, гарантирующий
//невозможность перехода в другое состояние, если задача
//либо успешно завершена, либо успешно отменена
//------------------------------------------------------
if ((m_processingState == ProcessingState.aborted) ||
(m_processingState == ProcessingState.foundPrime)) {
return;
}
//Разрешить изменение состояния
m_processingState = nextState;
}
public ProcessingState getProcessingState {
get {return m_processingState;}
}
//------------------------
//Возвращает простое число
//------------------------
public long getPrime() {
if (m_processingState != ProcessingState.foundPrime) {
throw new Exception("простое число еще не найдено!");
}
return m_NextHighestPrime;
}
//Конструктор класса
public FindNextPrimeNumber(long startPoint) {
setProcessingState(ProcessingState.notYetStarted);
m_startPoint = startPoint;
}
//-----------------------------------------------------------
//Создает новый рабочий поток, который будет вызывать функцию
// "findNextHighestPrime()"
//-----------------------------------------------------------
public void findNextHighestPrime_Async() {
System.Threading.ThreadStart threadStart;
threadStart = new System.Threading.ThreadStart(findNextHighestPrime);
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(threadStart);
//Состояние должно отвечать, что поиск продолжается
setProcessingState(ProcessingState.waitingToStartAsync);
newThread.Start();
}
//-------------------------------------------------------------
//Основной рабочий поток. Этот поток запускает поиск очередного
//простого числа и выполняется до тех пор, пока не произойдет
//одно из следующих двух событий:
// (а) найдено очередное простое число
// (b) от внешнего (по отношению к данному) потока поступила
// команда прекратить выполнение
//-------------------------------------------------------------
public void findNextHighestPrime() {
//Если поступила команда прекратить выполнение, то поиск
//даже не должен начинаться
if (m_processingState == ProcessingState.requestAbort) {
goto finished_looking;
}
//Состояние должно отвечать, что поиск продолжается
setProcessingState(ProcessingState.lookingForPrime);
long currentItem;
//Проверить, является ли число нечетным
if ((m_startPoint & 1) == 1) {
//Число является нечетным, начать поиск со следующего нечетного числа
currentItem = m_startPoint + 2;
} else {
//Число является четным, начать поиск со следующего нечетного числа
currentItem = m_startPoint + 1;
}
//Приступить к поиску простого числа
while (m_processingState == ProcessingState.lookingForPrime) {
//B случае нахождения простого числа возвратить его
if (isItemPrime(currentItem) == true) {
m_NextHighestPrime = currentItem; //Обновить состояние
setProcessingState(ProcessingState.foundPrime);
}
currentItem = currentItem + 2;
}
finished_looking:
//Выход. К этому моменту либо от другого потока поступила
//команда прекратить поиск, либо было найдено и записано
//следующее наибольшее простое число
//Если поступил запрос прекратить выполнение,
//сообщить, что выполнение процесса прекращено
if (m_processingState == ProcessingState.requestAbort) {
setProcessingState(ProcessingState.aborted);
}
}
//Вспомогательная функция, которая проверяет, является
//ли число простым
private bool isItemPrime(long potentialPrime) {
//Если число — четное, значит, оно не является простым
if ((potentialPrime & 1) == 0) {
return false;
}
//Продолжать поиск до тех пор, пока не будет превышено
//значение квадратного корня из числа
long end_point_of_search;
end_point_of_search = (long)System.Math.Sqrt(potentialPrime) + 1;
long current_test_.item = 3;
while (current_test_item <= end_point_of search) {
//---------------------------------------------------------
//Проверить, не поступила ли команда прекратить выполнение!
//---------------------------------------------------------
if (m_processingState != ProcessingState.lookingForPrime) {
return false;
}
//Если число делится без остатка,
//значит, оно не является простым
if (potentialPrime % current_test_item == 0) {
return false;
}
//увеличить число на два
current_test item = current_test_item + 2;
//------------------------------------------
//Увеличить количество проверенных элементов
//------------------------------------------
//ПРИМЕЧАНИЕ. Мы используем блокирование потока для уверенности в том,
//что эти значения не считываются во время выполнения операции
//их записи. Поскольку доступ к m_comparisonsSoFar
//и m_CurrentNumberBeingExamined могут осуществлять
//одновременно несколько потоков, любая выполняемая над ними
//операция записи/считывания должна синхронизироваться с "блокировкой",
//что будет гарантировать "атомарность" этих операций
lock(this) {
m_CurrentNumberBeingExamined = potentialPrime;
m_comparisonsSoFar++;
}
}
//Число является простым
return true;
} //Конец функции
} //Конец класса
Резюме
Фоновые потоки, если только их правильно использовать, могут пригодиться вам для улучшения условий интерактивного взаимодействия конечного пользователя с мобильным приложением за счет повышения способности пользовательского интерфейса к отклику. Фоновые потоки необходимо использовать умеренно, для вполне конкретных целей и лишь в тех случаях, когда они могут помочь вам справиться с реальными трудностями, связанными с обеспечением приемлемых интерактивных свойств приложения, которые не могут быть разрешены при использовании высокоприоритетного потока. Лучше всего проектировать приложение на основе однопоточной модели, привлекая фоновую обработку лишь тогда, когда вы убеждены в ее необходимости.
При написании кода фоновых потоков и проектировании классов, к которым могут иметь доступ одновременно несколько потоков, следует проявлять особую осторожность. Весьма полезно тщательно документировать код приложения, явно указывая, к каким его фрагментам будут пытаться получить доступ одновременно несколько потоков, а к каким, что не менее важно, не будут. Постарайтесь, чтобы количество классов, функций, свойств и переменных-членов, которые должны совместно использоваться несколькими потоками, было как можно меньшим, и уделите повышенное внимание к проектированию, анализу, тестированию и документированию соответствующих фрагментов кода.