Программирование систем реального времени презентация

Содержание

Производственные процессы обычно управляются группой связанных друг с другом ЭВМ, каждая из которых решает свои задачи. Способ программирования в основном зависит от требуемого времени реакции. На верхних уровнях управленческой иерархии

Слайд 1Программирование систем реального времени


Слайд 2Производственные процессы обычно управляются группой связанных друг с другом ЭВМ, каждая

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

Для создания эффективных систем управления реального времени программные средства (software) так же важны, как и аппаратные (hardware).
Технические средства и программы являются логически эквивалентными. Аппаратные средства должны обладать достаточными ресурсами, а программные – эффективно их использовать.
Программное обеспечение может свести на нет все достоинства вычислительного оборудования.


Слайд 3Последовательное программирование
Программа – это описание объектов (констант и переменных) и операций,

совершаемых над ними. Программа – это чистая информация.

Наиболее распространенный способ написания программ – это последовательное программирование Оно подразумевает, что операторы (команды) программы выполняются в определённой, заранее известной последовательности.
Целью последовательной программы (ПП) является преобразование входных данных, заданных в определенной форме, в выходные данные, имеющие другую форму, в соответствии с некоторым алгоритмом – методом решения.

Рис.1. Обработка данных последовательной программой

ПП работает как фильтр для исходных данных. Результат полностью определяются входными данными и алгоритмом их обработки. Временные показатели играют второстепенную роль.
Результат не зависит ни от инструментальных (определяют усилия и время, затраченные на разработку и характеристики исполняемого кода) ни аппаратных средств (определяют скорость выполнения программы). В любом случае результаты (выходные данные) будут одинаковыми.


Слайд 4Параллельное программирование − независимые программные модули или задачи, которые выполняются (активны)

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

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

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


Слайд 5Программы и процессы
Основным объектом в СРВ является задача, процесс (task, process).

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

области кода, т.е. инструкций программы;
области данных, в которой хранятся переменные и константы;
область свободной, динамически распределяемой рабочей памяти (heap – куча);
область стека, который примыкает к куче и расширяется за ее счёт

Рис.2. Организация внутренней памяти процесса


Слайд 6Программа, написанная на одном и том же языке высокого уровня, а

затем откомпилированная и исполняемая на разных ЭВМ, порождает различные процессы, каждый из которых имеет собственные области команд и данных, кучу и стек.

Каждый процесс в любой момент времени находится в точно определенном состоянии, однозначно описываемом некоторой базовой информацией (например, содержимое регистров процессора, расположение областей кода, данных и стека и т.д.) называемой – контекстом.

Существование контекста − это общее свойство процессов, а то, какие регистры, структуры и указатели реально являются частью контекста, зависит от используемого процессора и операционной системы.

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

Слайд 7Программирование в реальном времени требует одновременного исполнения нескольких процессов на одной

ЭВМ.
Процессы совместно используют вычислительные ресурсы системы, но более или менее независимы друг от друга.

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

Параллельное программирование,
мультипрограммирование и многозадачность

Рис. 3. Граф очерёдности исполнения процессов


Слайд 8Пара операторных скобок начало-конец (в С это { }, в Pascal

это begin-end) приводит к генерации потоков в рамках многозадачной системы. Исполнение команд между ключевыми словами начало и конец происходит параллельно.
Оператор начало не накладывает условий на относительный порядок исполнения отдельных процессов, а оператор конец достигается только тогда, когда все процессы внутри блока завершены.
Для параллельных процессов конечный результат однозначно предсказать нельзя; задачи выполняются, по крайней мере с внешней точки зрения, в случайной последовательности.

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


Слайд 9Снижение стоимости аппаратной части сделало экономически целесообразным применение вычислительных систем с

несколькими процессорами.
Распределенные системы используются для управления сложными процессами.
Основные преимущества распределенных систем:

Управление системными ресурсами.
Однопроцессорная и распределенная архитектуры

экономичность;
надежность (при отказе одного или нескольких процессоров остальные продолжают работать);
возможность подобрать аппаратные средства в соответствии с конкретными требованиями.

Методы достижения распределения вычислительных ресурсов:

Единственным общим ресурсом является вычислительная сеть, соединяющая ЭВМ, каждая из которых работает независимо и лишь обменивается сообщениями с остальными.
Реально распределенная сетевая операционная система, предоставляет пользователю гомогенную среду, не зависящую от аппаратной платформы. Пользователь может вводить произвольные команды, а операционная система находит наиболее подходящий способ и место их выполнения.


Слайд 10Главным различием между однопроцессорной и распределенной архитектурами является способ обмена информацией

между процессами. Эта процедура наиболее важна при мультипрограммировании и программировании в реальном времени

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

В распределенной системе нет общей памяти как таковой, и процессы обмениваются информацией с помощью сообщений. Если один процесс должен передать информацию другому, то он формирует сообщение и обращается к услугам операционной системы для передачи его по назначению. Этот принцип взаимодействия лежит в основе одной из наиболее важных концепций распределенных операционных систем – модели клиент-сервер

Процесс либо запрашивает услуги – он клиент, либо предоставляет их – он сервер. Очевидно, что один и тот же процесс может быть как клиентом, так и сервером.

"Услуга" – это некоторая законченная (замкнутая) операция, например, выполнение расчетов, приём внешних данных, операция с устройством ввода-вывода, вывод изображения на экран и т.д.


Слайд 11Модель клиент-сервер
1. Процессы, реализующие некоторую службу, например службу файловой системы или

базы данных, называются серверами (servers).
2. Процессы, запрашивающие службы у серверов путем посылки запроса и последующего ожидания ответа от сервера, называются клиентами (clients).

В базовой модели клиент-сервер все процессы в распределенных системах делятся на две возможно перекрывающиеся группы.

уровень пользовательского интерфейса;
уровень обработки;
уровень данных.

Уровни приложений в модели клиент-сервер:

Взаимодействие клиента и сервера, известно также под названием режим работы запрос-ответ (request-reply behavior)

Рис. 4. Взаимодействие клиента и сервера


Слайд 12Уровень пользовательского интерфейса

Уровень пользовательского интерфейса обычно реализуется на клиентах. Этот

уровень содержит программы, посредством которых пользователь может взаимодействовать с приложением.

Уровень обработки

Многие приложения модели клиент-сервер построены как бы из трех различных частей:

Уровень данных

Уровень данных в модели клиент-сервер содержит программы, которые предоставляют данные обрабатывающим их приложениям. Специфическим свойством этого уровня является требование сохранности (persistence). Это означает, что когда приложение не работает, данные должны сохраняться в определенном месте в расчете на дальнейшее использование.
Уровень данных обычно также отвечает за поддержание целостности данных для различных приложений.

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


Слайд 13Модель "клиент-сервер" можно рассматривать как расширенный вариант обращения к подпрограмме, при

котором сервер играет роль подпрограммы или системной процедуры.

Модель "клиент-сервер" основана на обмене сообщениями между программами. Если клиент и сервер исполняются на разных ЭВМ, а сообщения передаются через сеть, то система является распределенной.

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

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

Например.
В хорошо спроектированной системе сообщения содержат информацию о цели ("установить опорное значение t = 36.6º), а не о методах её достижения, например, "каково значение t: в данный момент?, t = 23º, тогда "увеличить t на 13,6º, "каково t сейчас?", t = 39º, тогда уменьшить на 3,4º, и т.д.).

Промежуточные шаги выполняются локально при условии, что программное обеспечение спроектировано соответствующим образом.

Слайд 14

Операционная система (ОС) − это сложный программный продукт, предназначенный для управления

аппаратными и программными ресурсами вычислительной системы.

ОС предоставляет каждому процессу «виртуальную» (логическую) среду, включающую в себя время процессора и память.
«Виртуальная среда» работает как прослойка между приложением и операционной системой, что позволяет избежать конфликтов между приложениями. Ее характеристики могут как совпадать, так и не совпадать с параметрами реального оборудования.

Функции операционных систем в среде реального времени

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


Слайд 15Системы разделения времени, или многопользовательские системы, большое внимание уделяют защите и

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

В распределенной среде операционная система дополнительно выполняет функции сопряжения программ с вычислительной сетью и управления обменом данными и сообщениями между ЭВМ.

В сетевых операционных системах каждая ЭВМ имеет высокую степень автономности. Общесистемные требования к обмену информацией позволяют взаимодействовать процессам, даже если они работают под управлением разных операционных систем, при условии, что каждая из них обладает необходимыми сетевыми возможностями.


Слайд 16Распределенные операционные системы
Распределенная операционная система – это общий термин, обозначающий решения

с различным уровнем функциональности.
Распределенная операционная система может представлять собой средство сетевого взаимодействия, сетевую файловую систему с единым интерфейсом или даже совокупность независимых ЭВМ, которую пользователи системы воспринимают как единую ЭВМ.

Рис. 5. Операция копирования файла

Рис. 6. Страницы единого (сетевого) адресного пространства


Слайд 17Основными объектами в многозадачной среде являются задачи или процессы, описываемые своим

контекстом.

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

Управление процессором и состояния процесса

Рис. 7. Принцип организации многозадачного режима.

Внешний эффект одновременного исполнения нескольких процессов , с точки зрения пользователя

Реальное распределение времени процессора


Слайд 18Процессор это ограниченный ресурс, который распределяется между всеми задачами.

На одном процессоре

для организации многозадачного режима выполнение каждой задачи разбивается на несколько коротких интервалов. Процессор выполняет часть первой задачи, затем второй, третьей и т.д.

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

Системная программа, выбирающая один из готовых для исполнения процессов, называется планировщиком.

Планировщик работает как один из процессов, но самый главный, который автоматически получает управление после каждого прерывания текущего процесса.

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

Слайд 19Операции по переключению процессов критичны по времени и должны осуществляться с

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

Планировщик вызывается обычно после обработки каждого прерывания.

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

При возникновении прерывания исполнение текущего процесса приостанавливается и проверяется, должен ли быть прерван текущий процесс и загружен новый.

Принудительная приостановка текущего процесса для передачи управления другому процессу называется вытеснением.

Слайд 20Продолжительность кванта времени влияет на производительность системы.
При коротком кванте улучшается

общее время обслуживания коротких процессов.
Если величина кванта сопоставима со временем, необходимым для переключения процессов, то большая часть ресурсов процессора будет уходить на планирование и переключение.
Если величина кванта слишком большая, увеличивается время ожидания процессов и, соответственно, время реакции.

Процесс исполняется до тех пор, пока не произойдет одно из следующих событий:

истек выделенный ему квант времени;
процесс заблокирован, например, ждет завершения операции ввода/вывода;
процесс завершился;
вытеснен другим процессом, имеющим более высокий приоритет, например, обработчиком прерываний.


Слайд 21В многозадачной среде процесс может находиться в одном из трех состояний
Готов.

Процесс может начать исполнение, как только освободится процессор.
Исполнение. Процесс исполняется в данный момент, т. е. процессор исполняет его код.
Ожидание, заблокирован. Для продолжения работы процессу не хватает какого-либо ресурса, за исключением ЦП, либо он ждет наступления внешнего события.

Рис. 8. Состояния процессов


Слайд 22От "Загрузочный модуль на диске" к "Готов". Программа загружается в оперативную

память, настраиваются относительные адреса, определяется контекст, т.е. выделяются рабочие области для данных, кучи и стека с соответствующими указателями.
От "Готов" к "Исполнение". Планировщик выбирает первый в очереди готовых процессов и передает ему управление.
От "Исполнение" к "Готов". Процесс либо исчерпал свой квант времени, либо появился готовый для исполнения процесс с более высоким приоритетом.
От "Исполнение" к "Ожидание". Для дальнейшего развития процесс должен ждать наступления какого-либо внешнего события (завершения операции ввода/вывода или освобождения ресурса, например доступа к памяти, заблокированной другим процессом, или сигнала от другого процесса и т. п.). Иногда процесс переводится в состояние ожидания до истечения некоторого интервала времени с помощью явной инструкции в его программе.
От "Ожидание" к "Готов". Когда ожидаемое событие произошло или истекло заданное время, процесс переводится в состояние "Готов" и помещается в очередь готовых процессов, откуда затем выбирается планировщиком.
После выполнения последней инструкции программы операционная система удаляет процесс из памяти и освобождает все выделенные ему ресурсы, включая память.

Слайд 23Для определения той или иной стратегии необходимо принять во внимание несколько

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

Отсюда Стратегии выбора процесса


Циклический метод. Наиболее простая стратегия. Процессы выбираются последовательно один за другим в фиксированном порядке и через равные интервалы времени. Основное достоинство метода − простота реализации. Недостаток, поскольку процессы имеют различные требования к выделяемым ресурсам вычислительной системы, то некоторые из них обслуживаются неадекватно своим потребностям.

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


Слайд 24Разница в первоначально назначенных приоритетах приводит к тому, что процессы с

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

Планирование процессов, основанное на приоритетах, работает хорошо, только если разные процессы имеют неодинаковые приоритеты.

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

Система, в которой всем процессам присвоены одинаковые приоритеты, работает по циклическому принципу. Наилучшие результаты достигаются в системе реального времени, если относительные приоритеты тщательно выбраны и сбалансированы.

Нетривиальным является также выбор между процессами с одинаковым приоритетом. Для исключения подобной ситуации применяется какой-либо алгоритм динамического назначения приоритетов


Слайд 25Немаскируемые прерывания, которые жестко связаны с рядом системных функций процессора и

имеют наивысший уровень приоритета.
Маскируемые прерывания.
High (высокий). Запросы на прерывание, которым присвоен статус High, обслуживаются немедленно после поступления, даже если центральный процессор сильно загружен.
Medium (средний)
Low (низкий).

При поступлении запроса на обслуживание прерывания с более высоким уровнем приоритета процесс обработки прерывания с более низким уровнем приостанавливается, и процессор начинает обрабатывать более значимый запрос.
Обслуживание прерываний может быть организовано в статическом или динамическом порядке.
В микроконтроллерах XMEGA немаскируемые прерывания, а также прерывания уровня High и Medium имеют только статический порядок обслуживания. Для прерываний с уровнем Low программисту доступна статическая и динамическая организация очередности обслуживания.

Контроллер прерываний контроллера Atmel XMEGA поддерживает 4-х уровневый процесс обслуживания – всем запросам на прерывание могут быть присвоены определенные уровни приоритета для обработки.

Многоуровневый контроллер прерываний


Слайд 26
Чтобы избежать возможных проблем с недоступностью обработчиков прерываний уровня Low в

соответствии со статическим порядком обслуживания, контроллер прерываний предоставляет возможность динамического перераспределения очередности – циклический алгоритм диспетчеризации (Round Robin) при котором все процессы активизируются в фиксированном циклическом порядке. Иногда этот алгоритм еще называют «карусельной диспетчеризацией».
Для этого в состав контроллера прерываний добавлен специальный регистр INTPRI. Когда процедура диспетчеризации Round Robin разрешена, в этом регистре запоминается вектор прерывания с уровнем Low, которое обслуживалось последним. Сохраненный вектор по отношению к его следующему вызову будет теперь иметь наименьший приоритет.

Процедура Round Robin эффективно работает в тех случаях, когда в очереди находятся несколько разрешенных прерываний из уровня Low, которые будут обслуживался в фиксированном циклическом порядке.

Рис. 9.. Процедура «карусельной диспетчеризации» Round Robin


Слайд 27Время отклика CPU для всех разрешенных прерываний составляет как минимум 5

тактов системной частоты.
За это время содержимое программного счетчика сохраняется в стеке.
Затем выполняется безусловный переход на программу – обработчик прерывания, что занимает еще 3 такта.
Если микроконтроллер находится в одном из энергосберегающих режимов, время реакции на исполнение увеличивается еще на 5 тактов плюс на время выхода микроконтроллера из текущего режима энергосбережения.
Также надо учитывать, что перед началом обслуживания любого запроса на прерывание процессорное ядро всегда завершает выполнение текущей инструкции на что естественно также уходит какое-то время.

Время отклика CPU на поступивший запрос на прерывание


Слайд 28Система событий
Система событий (Event System) Atmel XMEGA предназначена для разгрузки центрального

процессора. Используя сложную структуру матрицы соединений, периферийные узлы, процессорное ядро и контроллер DMA могут непосредственно обмениваться между собой как служебной, так и командной информацией, а также передавать и принимать данные.
Система событий предоставляет гибкость в предоставлении прав каждому из подключенных к ней периферийных модулей. Эти модули могут определять, по какому из внешних воздействий может генерироваться событие (заранее программируются пользователем), например, при перепаде напряжения на выводе микроконтроллера, при переполнении таймера, завершении цикла преобразования АЦП и т.д. Периферийные модули могут программироваться и на то, каким образом интерпретировать поступающее к ним событие – инкрементировать таймер, выставить выходной сигнал на выводе микросхемы, начать преобразование АЦП и т.д.
Система событий разгружает систему прерываний XMEGA за счет уменьшения количества формируемых запросов на прерывание. При этом значительно повышается надежность обработки данных и принятия решений. Критичные ко времени или к стабильности выполнения функции теперь становятся более прогнозируемыми, а значит, увеличивается надежность работы всей системы в целом. Также снижается загрузка центрального процессора для обработки различных «несистемных» прерываний, генерируемых периферийными узлами и модулями, в том числе и какими-то внешними событиями.

Слайд 29Генерация события занимает два периода системной тактовой частоты. Поэтому временные параметры

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

Рис. 10. Блок-схема Event System


Обратная связь

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

Email: Нажмите что бы посмотреть 

Что такое ThePresentation.ru?

Это сайт презентаций, докладов, проектов, шаблонов в формате PowerPoint. Мы помогаем школьникам, студентам, учителям, преподавателям хранить и обмениваться учебными материалами с другими пользователями.


Для правообладателей

Яндекс.Метрика