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

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

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

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

PtWorkProcId_t *WorkProc_id );

передавая ей тот же контекст приложения и указатель, возвращённый функцией PtApppAddWorkProc().

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

#include <Pt.h>

typedef struct workDialog {

PtWidget_t *widget;

PtWidget_t *label;

PtWidget_t *ok_button;

} WorkDialog_t;

typedef struct countdownClosure {

WorkDialog_t *dialog;

int value;

int maxvalue;

int done;

PtWorkProcId_t *work_id;

} CountdownClosure_t;

WorkDialog_t *create_working_dialog(PtWidget_t *parent) {

PhDim_t dim;

PtArg_t args[3];

int nargs;

PtWidget_t *window, *group;

WorkDialog_t *dialog = (WorkDialog_t *) malloc(sizeof(WorkDialog_t));

if (dialog) {

dialog->widget = window = PtCreateWidget(PtWindow, parent, 0, NULL);

nargs = 0;

PtSetArg(&args[nargs], Pt_ARG_GROUP_ORIENTATION, Pt_GROUP_VERTICAL, 0);

nargs++;

PtSetArg(&args[nargs], Pt_ARG_GROUP_VERT_ALIGN, Pt_GROUP_VERT_CENTER, 0);

nargs++;

group = PtCreateWidget(PtGroup, window, nargs, args);

nargs = 0;

dim.w = 200;

dim.h = 100;

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

PtSetArg(&args[nargs], Pt_ARG_TEXT_STRING, "Counter: ", 0); nargs++;

dialog->label = PtCreateWidget(PtLabel, group, nargs, args);

PtCreateWidget(PtSeparator, group, 0, NULL);

nargs = 0;

PtSetArg(&args[nargs], Pt_ARG_TEXT_STRING, "Stop", 0); nargs++;

dialog->ok_button = PtCreateWidget(PtButton, group, 1, args);

} // if(dialog)

return dialog;

} // create_working_dialog()

int done(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

CountdownClosure_t *closure = (CountdownClosure_t *)client;

call = call;

if (!closure->done) { PtAppRemoveWorkProc(NULL, closure->work_id); }

PtDestroyWidget(closure->dialog->widget);

free(closure->dialog);

free(closure);

return (Pt_CONTINUE);

} // done()

int count_cb(void *data) {

CountdownClosure_t *closure = (CountdownClosure_t *)data;

char buf[64];

int finished = 0;

if ( closure->value++ = = 0 || closure->value % 1000 = = 0 ) {

sprintf(buf, "Counter: %d", closure->value);

PtSetResource( closure->dialog->label, Pt_ARG_TEXT_STRING, buf, 0);

}

if ( closure->value = = closure->maxvalue ) {

closure->done = finished = 1;

PtSetResource( closure->dialog->ok_button, Pt_ARG_TEXT_STRING, "Done", 0);

}

return finished ? Pt_END : Pt_CONTINUE;

} // count_cb()

int push_button_cb(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

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() – когда разблокируетесь.

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

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

Список файлов учебной работы

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