Исходные коды: С++
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:14 | Сообщение # 16 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| В этом примере показано взаимодействие двух параллельных процессов: сценарий передает процессу Т сообщение целого типа, а процесс Т принимает его и отображает принятое значение. Обмен сообщениями реализован в библиотеке на основе понятия "канал". Канал - это параметризованный экземпляр класса, порожденного от базового класса ТКанал. Канал формирует собственную очередь сообщений. Сообщения ставятся в очередь в порядке их поступления (дисциплина FIFO). Канал является типизируемой структурой данных - это означает, что тип сообщений, который канал может обрабатывать, явно определен и известен на момент компиляции. Для декларации канала используются шаблоны (templates). Синтаксис декларации канала следующий: Code ТКанал<тип_сообщения> имя_канала; Тип сообщения (указываемый в угловых скобках) может быть любым предопределенным типом или типом, который определил программист, например, запись (struct). В нашем случае декларируется, что создается канал целого типа (int). В примере канал определен как доступный член процесса Т, но такая принадлежность не является обязательной - канал это самостоятельный объект и может быть декларирован независимо от процесса. Процесс может использовать множество каналов, в том числе и однотипных. Массив однотипных каналов удобно использовать для организации системы приоритетных очередей.
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:15 | Сообщение # 17 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Для канала определены две основных операции: передать в канал << и принять из канала >>. В обоих случаях в левой части операторов должно стоять имя канала, а в правой части - имя переменной, тип которой соответствует типу канала. Семантика оператора >> (принять) состоит в следующем: вначале проверяется, есть ли в очереди канала сообщения: если есть, то из очереди выбирается первое сообщение и процесс, выполнивший операцию приема, продолжает выполняться дальше без задержки. Если же очередь канала пуста, то процесс переводится из очереди готовых процессов в очередь ожидания событий. Отметим, что ожидать сообщения в канале в один момент времени может только один процесс, попытка выполнения операции приема из канала, в котором уже ожидает некоторый процесс, является ошибкой и приведет к аварийному завершению программы с выдачей диагностического сообщения. Семантика оператора << (передать) состоит в том, что сообщение упаковывается в конверт и ставится в конец очереди сообщений канала. Процесс, выполнивший операцию передачи при этом не приостанавливается, а продолжает выполняться дальше. Длина очереди канала не ограничена. При выполнении оператора передачи проверяется, есть ли у канала ожидающий процесс, если есть, то он активизируется, т.е. переводится в очередь готовых процессов. Таким образом, каналы предоставляют процессам буферизованный несимметричный механизм взаимодействия, в котором получатель сообщения приостанавливается при отсутствии сообщений, а процесс, передающий сообщение, всегда выполняется без приостановки. Кроме основных операций << (передачи) и >> (приема) для канала определена также операция <<= (передача в начало канала). В отличие от операции <<, которая записывает сообщения в конец очереди канала, операция <<= записывает сообщения в начало очереди канала. Таким образом, структура канала является промежуточной между очередью и деком: в такую очередь можно записывать данные с обоих концов, а удалять только из начала. Операция <<= может быть использована для различных целей, например:
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:15 | Сообщение # 18 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| * для посылки особо приоритетных сообщений, * для возврата полученного сообщения обратно в канал для последующей обработки, * для возврата полученного и модифицированного сообщения в канал. Возврат сообщений удобно использовать в программах, управляемых событиями. Кроме того, канал предоставляет еще несколько сервисных функций: * функция корреспондент() возвращает указатель на процесс, передавший данное сообщение, * функция пуст() возвращает логическую 1 при отсутствии сообщений в канале, * функция таймаут() позволяет задать предельное время ожидания сообщения в канале, например, вызов: канал.таймаут(1000); будет устанавливать время таймаута, равное 1 секунде. Это означает, что если процесс, выполнивший операции >> (принять) ждет сообщения больше 1 секунды, то он активизируется, причем значение переменной - приемника сообщения не изменяется. Для реализации этой возможности оператор >> возвращает логическую 1, если прием сообщения был удачным и 0, если зафиксирован таймаут. Например:
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:15 | Сообщение # 19 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Code if (канал >> i) cout << "Принято сообщение " << i << '\n'; else cout << "Таймаут\n";
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:15 | Сообщение # 20 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Введение таймаута позволяет элегантно решать задачи, возникающие при приеме сообщений от потенциально ненадежного источника сообщений без зависания программы.
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:16 | Сообщение # 21 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Программа 7 Quote enum ТТег { целое, строка }; struct ТКонтейнер_Целого { int значение; }; struct ТКонтейнер_Строки { char значение[10]; }; ТКанал<ТТег> канал_тега; ТКанал<ТКонтейнер_Целого> канал_целых; ТКанал<ТКонтейнер_Строки> канал_строк; простой_процесс(ТГенератор_Целых) { ТТег тег = целое; ТКонтейнер_Целого контейнер; контейнер.значение = 123; пауза(случайное_число(10, 60)); канал_тега << тег; канал_целых << контейнер; } простой_процесс(ТГенератор_Строк) { ТТег тег = строка; ТКонтейнер_Строки контейнер; strcpy(контейнер.значение, "ABCDEF"); пауза(случайное_число(10, 60)); канал_тега << тег; канал_строк << контейнер; } static ТГенератор_Строк генератор_строк; static ТГенератор_Целых генератор_целых; void ТСценарий::тело_процесса(void) { ТТег тег; ТКонтейнер_Целого контейнер_целого; ТКонтейнер_Строки контейнер_строки; канал_тега.таймаут(30); if (канал_тега >> тег) { switch (тег) { case целое: канал_целых >> контейнер_целого; break; case строка: канал_строк >> контейнер_строки; break; } } else cout << "Таймаут\n"; }
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:16 | Сообщение # 22 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Этот пример демонстрирует реализацию операции недетерминированного ожидания (ее семантика напоминает семантику оператора select языка Ада или блока ALT языка Оккам). В программе определяются следующие объекты: * два статических процесса, генерирующих сообщения разного типа: целого и строки; * два канала для передачи сообщений указанных типов; * один канал для передачи тега - типа сообщения. Для этого канала вводится ограничение по таймауту в 30 миллисекунд; * процесс-сценарий, принимающий сообщения. Каждый из статических процессов заполняет свои контейнеры сообщений и передает их в соответствующие каналы. Кроме того, передача контейнера сообщения сопровождается передачей типа сообщения в канал тега. Время передачи определяется случайным числом в диапазоне от 10 до 60 миллисекунд. Сценарий принимает тип сообщения из канала тега и, в зависимости от того, какое из трех событий (2 сообщения и таймаут) наступило быстрее, выполняет то или иное действие. В этом примере используется техника сильной типизации сообщений: вместо предопределенных типов "int" и "char[]" сообщения определяются как записи (struct), содержащие всего по одному элементу. Отметим также, что все каналы создаются как самостоятельные объекты (не принадлежащие конкретному процессу). Для определения процессов в примере используется макроопределение "простой_процесс()", аргумент которого - имя типа процесса. Это макроопределение позволяет более лаконично записывать декларацию типа процесса и его тела в часто используемом случае, когда процесс переопределяет только одну функцию базового класса: тело_процесса(). Таким образом, лаконичное определение процесса Т:
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:16 | Сообщение # 23 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Code простой_процесс(Т) { пауза(1000); }
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:16 | Сообщение # 24 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| полностью эквивалентно такому явному определению: Code class Т : public ТПроцесс { public: void тело_процесса(void); };
void Т::тело_процесса(void) { пауза(1000); }
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:17 | Сообщение # 25 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Программа 8 Code ТРандеву<int> рандеву;
простой_процесс(ТПроизводитель) { int i = 0; for (;;) { пауза(случайное_число(1000, 6000)); рандеву << ++i; } }
простой_процесс(ТПотребитель) { int i; for (;;) { пауза(3000); рандеву >> i; } }
static ТПроизводитель производитель; static ТПотребитель потребитель;
void ТСценарий::тело_процесса(void) { пауза(20000); }
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:17 | Сообщение # 26 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| В этом примере иллюстрируется взаимодействие двух асинхронно выполняемых процессов - процесса-производителя, готового к взаимодействию через случайный промежуток времени в диапазоне от 1 до 6 секунд и процесса-потребителя, который готов к взаимодействию не ранее, чем через 3 секунды после взаимодействия с процессом-производителем. Взаимодействие выполняется на основе механизма "рандеву", синхронизирующего взаимодействие двух параллельных процессов. Семантика рандеву такова: если к взаимодействию готов только один процесс, то он приостанавливает свое выполнение (переводится в очередь ожидания событий) до того момента, когда к взаимодействию будет готов второй процесс, после чего оба процесса обмениваются данными и продолжают выполняться асинхронно. Рандеву обеспечивает небуферизованное симметричное взаимодействие процессов - оба процесса выступают как равноправные, в отличие несимметричного обмена сообщениями через канал. Синтаксис рандеву аналогичен синтаксису обмена сообщениями с тем отличием, что вместо канала используется параметризованный объект класса, порожденного от базового класса ТРандеву. Синтаксис операторов приема и передачи тот же. Для рандеву также можно ограничивать время ожидания, используя функцию таймаут().
Админ
|
|
|
|
MafiozikO | Дата: Воскресенье, 23.08.2009, 10:17 | Сообщение # 27 |
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
| Программа 9 Доступно только для пользователей Данный пример демонстрирует технику работы с устройством. Клавиатура (как устройство) - это статический процесс, создаваемый исполняющим ядром библиотеки. В отличие от традиционного способа, когда по ходу программы вызывается функция получения кода клавиши, в библиотеке 2KLIB используется обмен сообщениями. Для этого создается канал типа ТСобытие, который связывается с процессом "клавиатура". Связка выполняется с помощью функции, определенной в процессе "клавиатура" - соединить(). Аргументом этой функции является канал, в который клавиатура будет посылать сообщения о нажатых клавишах. Процесс, использующий клавишные события, выполняет операцию приема из данного канала.
Админ
|
|
|
|