Главная » Просмотр файлов » Руководство программиста в Photon

Руководство программиста в Photon (953920), страница 44

Файл №953920 Руководство программиста в Photon (Руководство программиста в Photon) 44 страницаРуководство программиста в Photon (953920) страница 442013-09-22СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 44)

PtWidget_t *parent = (PtWidget_t *)client;

WorkDialog_t *dialog;

w = w; call = call;

dialog = create_working_dialog(parent);

if (dialog) {

CountdownClosure_t *closure = (CountdownClosure_t *) malloc(sizeof(CountdownClosure_t));

if (closure) {

PtWorkProcId_t *id;

closure->dialog = dialog;

closure->value = 0;

closure->maxvalue = 200000;

closure->done = 0;

closure->work_id = id =

PtAppAddWorkProc(NULL, count_cb, closure);

PtAddCallback(dialog->ok_button, Pt_CB_ACTIVATE, done, closure);

PtRealizeWidget(dialog->widget);

} // if (closure)

} // if (dialog)

return (Pt_CONTINUE);

}

int main(int argc, char *argv[]) {

PhDim_t dim;

PtArg_t args[3];

int n;

PtWidget_t *window;

PtCallback_t callbacks[] = {{push_button_cb, NULL}};

char Helvetica14b[MAX_FONT_TAG];

if (PtInit(NULL) = = -1) PtExit(EXIT_FAILURE);

dim.w = 200;

dim.h = 100;

PtSetArg(&args[0], Pt_ARG_DIM, &dim, 0);

if ((window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 1, args)) = = NULL)

PtExit(EXIT_FAILURE);

callbacks[0].data = window;

n = 0;

PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, "Обратный отсчёт...", 0);

/* Используется шрифт Helvetica 14-пунктовый жирный, если тот доступен */

if (PfGenerateFontName("Helvetica", PF_STYLE_BOLD, 14, Helvetica14b) = = NULL) {

perror("невозможно сгенерировать имя шрифта");

}

else PtSetArg(&args[n++], Pt_ARG_TEXT_FONT, Helvetica14b, 0);

PtSetArg(&args[n++], Pt_CB_ACTIVATE, callbacks, sizeof(callbacks)/sizeof(PtCallback_t));

PtCreateWidget(PtButton, window, n, args);

PtRealizeWidget(window);

PtMainLoop();

return (EXIT_SUCCESS);

}

Когда нажимается кнопка, прикреплённая к ней ответная реакция создаёт рабочий диалог и добавляет рабочую процедуру, передавая в качестве параметра указатель closure на структуру, содержащую всю информацию, необходимую для выполнения отсчёта и очистки, когда отсчёт будет выполнен.

Параметр closure содержит указатель на диалог, текущее значение счётчика и значение, до которого ведётся отсчёт. Когда это значение будет достигнуто, рабочая процедура изменит надпись на кнопке диалога и подсоединит ответную реакцию, которая снесёт напрочь диалог в целом, когда кнопка будет нажата. Будучи так вынужденной, рабочая процедура вернёт Pt_END, чтобы быть удалённой.

Функция done() вызывается, если пользователь останавливает рабочую процедуру или если она завершает свою работу. Эта функция удаляет диалог, связанный с рабочей процедурой, и удаляет рабочую процедуру, если та была остановлена пользователем (т.е. она не выполнилась вплоть до завершения).

Если Вы запустите этот пример на исполнение, Вы можете обнаружить ещё одну из возможностей рабочих процедур – они вытесняют одна другую. Когда Вы добавляете новую рабочую процедуру, она вытесняет все остальные. Новая рабочая процедура отработает только один раз, пока не завершится или не будет удалена. После этого возобновится исполнение рабочей процедуры, исполнявшейся до этого. Это проиллюстрировано в вышеприведенном примере – в случае, когда пользователь нажимает кнопку "Count Down..." до того, как отсчёт завершится. Создаётся новый диалог отсчёта, и этот отсчёт будет исполняться вместо первого, пока не выполнится.

Уровень модульности этой вытесняемости – на уровне вызова функции. Когда функция ответной реакции для рабочей процедуры вернёт управление, эта рабочая процедура может быть вытеснена другой рабочей процедурой.

Потоки

Приложения Photon'а являются приложениями, управляемыми событиями и базирующимися на ответных реакциях; каждый раз, когда приходит событие, вызывается соответствующая ответная реакция и обрабатывает это событие, и затем управление возвращается в петлю событий на ожидание следующего события. В связи с такой структурой большинство приложений Photon'а являются однопоточными. Библиотека Photon'а позволяет Вам использовать потоки, но путём минимизации накладных расходов для однопоточных приложений. Библиотека Photon'а является скорее "дружественной по отношению к потокам", чем полностью потоко-безопасной, как функции printf() и malloc(), являющиеся потоко-безопасными.

 Не отменяйте поток, который может исполнять функцию библиотеки Photon'а или ответную реакцию (поскольку библиотека, возможно, должна выполнить какую-нибудь очистку, когда ответная реакция вернёт управление).

Этот раздел включает:

  • Запирание библиотеки Photon'а

  • Несколько потоков, обрабатывающих события

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

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

  • Модальные операции и потоки

  • Завершение многопоточной программы

  • Потоки и рабочие процедуры

Запирание библиотеки Photon'а

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

Чтобы написать Ваши не-Photon'овские потоки:

  • Поставьте вызовы функций PtEnter() и PtLeave() вокруг каких-либо вызовов Photon'овских функций в этих потоках.

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

  • Попытайтесь убрать весь не-Photon'овский код, который может забирать время для своего исполнения, из Вашей секции вход/выход – в противном случае он может безо всяких на то оснований препятствовать другим потокам в выполнении их работы.

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

Функция PtLeave() не передаёт автоматически библиотечный замок другому потоку, блокированному внутри PtEnter(); другой поток становится разблокированным, но затем он должен конкурировать со всеми другими потоками, как если бы он просто вызвал PtEnter(). Вы должны использовать функции PtEnter() и PtLeave() вместо своего собственного мутекса, потому что когда функция PtProcessEvent() (которую вызывает функция PtMainLoop() ) ожидает события, она отпирает библиотеку. Как только PtProcessEvent() получает некое событие, которое она может обработать, она вновь запирает библиотеку. Таким образом, Ваши не-Photon'овские потоки могут свободно получить доступ к функциям Photon'а, когда у Вас нет никаких событий для обработки.

Если Вы используете свой собственный мутекс, о котором PtProcessEvent() не знает, он отопрётся только тогда, когда его отопрёт Ваш код. Это означает, что только то время, когда Ваши не-Photon'овские потоки могут запереть мутекс, является временем, когда Ваше приложение обрабатывает событие, которое вызвало одну из Ваших ответных реакций. Не-Photon'овские потоки не могут запирать мутекс, когда приложение находится в состоянии ожидания.

Несколько потоков, обрабатывающих события

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

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

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

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

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

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

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

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

или

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

или

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

или

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

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

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

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

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

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

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

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

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

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

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

Не-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(), перед тем как выполнить возврат из ответной реакции.

Модальные операции и потоки

Модальная операция – это та, где Вам надо ожидать появления какого-то конкретного события перед тем, как Вы можете начать исполнение – например, когда Вы хотите, чтобы пользователь принял решение и нажал кнопку "Да" или "Нет". Поскольку обычно до того, как появится ожидаемое, обычно придут другие события, Вам надо гарантировать, что они обработаны.

В однопоточном приложении прикрепите ответную реакцию к кнопкам "Да" и "Нет". В этой ответной реакции вызовите PtModalUnblock(). Когда Вы отобразите диалог, вызовите функцию PtModalBlock(). Эта функция запустит петлю обработки событий, похожую на PtMainLoop(), за исключением того, что функция PtModalBlock() возвращает управление, когда что-нибудь (например, ответная реакция, прикреплённая к кнопкам "Да" и "Нет"), вызовет PtModalUnblock().

В многопоточном приложении функция PtModalBlock() может:

  • делать то же, что и однопоточном приложении

или

  • блокироваться на переменной состояния и позволить другим потокам Photon'а обрабатывать события.

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

Характеристики

Тип файла
Документ
Размер
7,62 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6417
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее