Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
76
Добавлен:
02.04.2015
Размер:
8.79 Mб
Скачать
      1. Несколько потоков, обрабатывающих события

Если вам требуется в Вашем приложении долго исполняемая ответная реакция, Вы можете сделать так, чтобы Ваша ответная реакция вызывала функцию PtBkgdHandlerProcess(), как было описано выше в этой главе. Вы можете также породить новый поток, для выполнения этой работы, вместо того чтобы делать её в ответной реакции.

Другим выбором является создание более одного Photon'овского потока, обрабатывающего события Photon'а в Вашем приложении. Вот так:

  • Породить один или более дополнительных потоков, которые вызывают функцию PtEnter() вслед за PtMainLoop(). Если один из Ваших Photon'овских потоков получает некое событие, которое вызывает Вашу долго выполняющуюся ответную реакцию, остальные потоки могут принимать на себя обработку событий Photon'а.

  • Вызвать функцию PtLeave() из ответной реакции, чтобы дать другим потокам доступ к библиотеку Photon'а.

  • Не забыть вызвать функцию PtEnter() перед выходом из ответной реакции; код, вызвавший Вашу ответную реакцию, расчитывает на собственный замок Photon'а, когда ответная реакция вернула управление.

 Отпирание библиотеки позволяет другим потокам модифицировать Ваши виджеты и глобальные переменные, пока Вы не видите, так что будьте внимательны.

Если Ваша ответная реакция позволяет другим потокам обрабатывать событие, пока она выполняет свою долго выполняющуюся операцию, имеется вероятность того, что пользователь, владеющий мышью, может нажать определённую кнопку вновь, вызывая вашу ответную реакцию до того, как та завершила выполнение своего первого вызова. Вы должны обеспечить, чтобы Ваше приложение либо корректно обрабатывало эту ситуацию, либо принять меры, чтобы такого не случалось. Вот несколько способов, как это осуществить:

  • Блокировать Вашу кнопку перед тем, как ответная реакция вызовет PtLeave(), и разблокировать её после вызова функции PtEnter()

или

  • Использовать флаг, указывающий повторно вызванной ответной реакции, что она уже запущена

или

  • Использовать счётчик, если вы хотите подсчитать, а не просто игнорировать все дополнительные нажатия кнопки

или

  • Использовать Ваш собственный мутекс или другой механизм синхронизации, чтобы гарантировать, что Вы не наступаете на свои собственные пятки (но остерегайтесь возможных тупиков).

      1. Потоки реального времени

Не создавайте вызовов Photon'овских функций в потоках, которые должны иметь детерминированное поведение, удовлетворяющее требованиям реального времени. Сложно прогнозировать, как долго будет продолжаться блокирование на PtEnter(); это может забрать время у потока, который владеет замком для завершения обработки текущего события или вызова PtLeave(), особенно если это касается отсылки сообщения другим процессам (таким как менеджер окон).

Лучше иметь "рабочий поток", удовлетворяющий требованиям к Вашим потокам реального времени, и исполнять этот поток в его собственной секции входа/выхода. Переменная состояния – и, возможно, очередь запросов – является хорошим способом отсылки этих запросов между потоками.

Если Вы используете рабочие потоки, и Вам надо использовать переменную состояния, вызовите вместо функции pthread_cond_wait() функцию PtCondWait() и отделите мутекс. Функция PtCondWait() использует замок библиотеки Photon'а как мутекс и исполняет безусловный вызов PtLeave(), когда Вы блокируетесь, и PtEnter() – когда разблокируетесь.

Потоки блокированы до тех пор, пока:

  • Они не получили доступ к библиотеке

  • Они не получили толчок от сигнала

  • Другой поток не выдал сигнал или трансляцию сигналов (broadcasts) переменной состояния.

  • Другой поток не вызвал PtExit(), exit() или _exit().

Функция PtCondTimedWait() похожа на PtCondWait(), но время блокирования ограничено тайм-аутом.

      1. Не-Photon'овские и Photon'овские потоки

Библиотека отслеживает, какие из Ваших потоков являются Photon'овскими (читающими сообщения), а какие – не-Photon'овскими (нечитающими). Таким образом, библиотека всегда знает, сколько Ваших потоков способно получать и обрабатывать события. Эта информация в настоящее время используется только функцией PtModaBlock() (см. раздел "Модальные операции и потоки" ниже).

По умолчанию, поток, вызвавший функцию PtInit(), является читателем событий, а все остальные – нет. Но если нечитающий поток вызывает функцию PtProcessEvent() или PtMainLoop(), он автоматически становится читающим события.

 Photon не запускает новых потоков для Вас, если Вы завершили Photon'овские потоки.Вы также можете превратить нечитающий поток в читающий и обратно, передавая флаг в функцию PtEnter() или PtLeave():

Pt_EVENT_PROCESS_ALLOW

Превратить вызывающий поток в читающий события

PtEVENT_PROCESS_PREVENT

Превратить вызывающий поток в нечитающий.

Если Вам не требуется изменять состояние потока (например, для не-Photon'овского потока, который никогда не обрабатывает никаких событий), не устанавливайте ни тот, ни другой из этих битов во флагах.

Если Вы вызываете функцию Pt_Leave() в ответной реакции, потому что собираетесь выполнить что-то достаточное длительное по времени, передайте функции PtLeave() признак Pt_EVENT_PROCESS_PREVENT. Это укажет библиотеке, что данный поток не собирается обрабатывать событие довольно значительный промежуток времени. Убедитесь, что передали Pt_EVENT_PROCESS_ALLOW функции PtEnter(), перед тем как выполнить возврат из ответной реакции.

Соседние файлы в папке Литература_1