Программирование систем ввода вывода

Общие методы программирования операций ввода-вывода

Один из самых важных методов программирования ввода-вывода — это метод, который следует избегать: принудительное ожидание устройства операционной системой. Почти у всех был опыт просмотра Microsoft Windows «заморозить». Иногда зависание происходит из-за сбоя, но в других случаях система просто ожидает ответа устройства.

Существует два основных метода программирования для работы с ожиданием устройства: синхронный и асинхронный. Синхронное программирование ожидает устройства, и его следует избегать. Асинхронное программирование использует другие методы (например, ожидание запросов прерывания). Дополнительные сведения об синхронном и асинхронном программировании см. в следующих разделах:

Microsoft Vista имеет новую политику для решения проблем с синхронным программированием. Дополнительные сведения об этой новой политике см. в разделе Ограничение ожиданий в Windows Vista .

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

Источник

5. Программирование ввода и вывода

5.1. Аппаратная реализация взаимодействия процессора с внешним устройством

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

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

Читайте также:  Программа где есть все языки программирования

При выполнении команды взаимодействия с ячейкой памяти или с портом ВУ (чтение/запись) используются шины (A,D,Control) соединяющие процессор с памятью и ВУ. Для обмена данными процессор сначала формирует адрес порта или ячейки, который с помощью специальной схемы дешифрируется, выявляя адресуемый порт или ячейку.

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

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

Идентификация используемого в процессе записи/чтения данных адресного пространства осуществляется с помощью сигнала IO/M. Нулевое значение этого сигнала идентифицирует режим работы с ячейками памяти, а единичное значение – указывает на режим взаимодействия с портами ВУ. При таком способе адресации портов, для взаимодействия с портами используются только специальные команды: для чтения данных IN Port, для записи данных OUT Port.

Признак IO/Mиспользуемый для идентификации типа адресного пространства формируется при дешифрации команды, если команда IN или OUT, то устанавливается единичное значение признака IO/M.

Для подачи данных на шину Dи приема данных с шиныDиспользуется двунаправленный шинный формирователь.

Два буферных регистра (один для приема, а другой для передачи данных), объединенных в единый функциональный блок, представляются в курсовом проекте, как буферный регистр с именем RD.

Функциональный блок RD размещается в процессоре и через управляемую двунаправленную шину Dподсоединяется к портам ВУ и к ячейкам памяти. Выбор соединения осуществляется управляющим сигналом IO/M.

Кроме буферного регистра RD, в процессоре размещается буферный регистр RA, содержимое, которого подается на шину А, соединенную со схемами дешифрации, размещенными во внешнем устройстве и в устройстве памяти. Нужная схема дешифрации активируется с помощью сигнала IO/M, подаваемого на вход CSмикросхемы дешифратора.

Для управления обменом данными используются также сигналы : Read, Writeдля памяти и сигналы: IOR, IOW для ВУ.

Работа ЭВМ заключается в выполнении командного цикла, состоящего из машинных циклов, таких как выборка команды (IFETCH), дешифрации кода операции (DECODE), формирование исполнительного адреса (EADDR), выборка операндов (OFETCH) и тому подобные. Машинный цикл в свою очередь делится на нужное количество тактов в зависимости от типа машинного цикла. На каждом такте выполняется микрооперация, напримерRA=RI[A], гдеRI[A] обозначает адресную информацию, размещенную в регистре командRI.

Отметим, что в анализируемой модели ЭВМ машинные циклы команд READ(WRITE) иIN(OUT) могут быть идентичными по описанию, но количество тактов (и микроопераций), требуемое для выполнения этих команд будет различное.

Так как в машинном цикле OFETCHописаны две последовательности микроопераций, то для идентификации последовательностей внутри машинного цикла используется признакIO/M.

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

Организация ввода данных с проверкой готовности ВУ к обмену.

Данные поступают от ВУ вместе с сигналом стробирования (STB), который служит для загрузки данных в буферный регистр RGI, и для установки признака готовности IBF (InputBufferFull) к обмену. Для хранения признака используется триггер TIBF , который соответствует седьмому биту регистра состояния процессора. Седьмой бит служит для оповещения о готовности порта внешнего устройства к обмену. КомандаINпрограммыCPUвводит данные с регистра состояния в аккумулятор и проверяет наличие единичного значения признака готовности. При наличии признака готовностиCPUосуществляет ввод данных с порта (RGI), хранящего данные. Сигналы дешифратораCSD и CSS служат для управления передачей данных между портом ВУ и регистромRD(аккумулятор) данных процессора.

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

Организация вывода данных с проверкой готовности ВУ к обмену.

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

Источник

Работа с потоками ввода-вывода в C++

Программа, выводящая в консоль сообщение Hello, world! , с которой традиционно начинают изучение языка программирования, на языке C++ выглядит следующим образом:

#include using namespace std; int main()  cout  <"Hello, world!"  <endl; return 0; > 

Директива #include и функция main() знакомы читателю по языку C. Способ вывода строки в консоль отличается от стандартной функции printf языка C и даёт нам повод начать разговор про C++.

Чтобы считать данные из стандартного потока ввода stdin , необходимо воспользоваться объектом cin и оператором извлечения >> .

Здесь мы снова построили цепочку вызовов и получили значения сразу для двух переменных. При обращении к потоку ввода мы не указывали тип данных, которые необходимо прочитать. Оператор >> сам определяет типы объектов и заполняет их из потока ввода.

Объекты cout , cin , а также операторы вставки и извлечения определены в заголовочном файле

Работа с файлами

Все операции ввода-вывода в C++ организованы через потоки и операторы > . Мы уже рассмотрели операции ввода-вывода в потоки stdout и stdin . Операции ввода-вывода с файлами устроены схожим образом. Для работы с файловыми потоками необходимо подключить заголовочный файл . Следующая программа создает файл test.txt и записывает в него строку Hello, world!

#include using namespace std; int main()  ofstream ofile("test.txt", ios::out); if (ofile.is_open())  ofile  <"Hello, world!"; > return 0; > 

Сначала мы создали объект типа ofstream . В его конструктор мы передали имя файла test.txt и флаг ios::out , указывающий на то, что мы собираемся осуществлять операции вывода. Всегда необходимо проверять, что операция открытия/создания файла прошла успешно. Если не выполнить эту проверку, то, если по какой-либо причине файл открыть не удалось, дальнейшие шаги приведут к аварийному завершению программы. Метод is_open() позволяет выполнить такою проверку. Дальше идет уже знакомый нам вызов оператора

Чтение данных из файла производится следующим образом:

#include #include #include using namespace std; int main()  ifstream ifile("test.txt", ios::in); if (ifile.is_open())  string line; while (ifile >> line)  cout  <line  <' '; > > return 0; > 

Здесь мы воспользовались файловым потоком ввода ifstream и флагом ios::in . В этой программе мы создали переменную line типа string , чтобы хранить считанные из файла данные. Неочевидным моментом здесь является использование цикла while . Дело в том, что оператор >> считывает символы до тех пор, пока не встретит разделитель (пробел, табуляция или перенос строки). Если бы мы вызвали этот оператор один раз, то в переменную line было бы записано Hello, , а это не то, чего мы хотели. Цикл позволяет прочитать файл до конца.

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

#include #include #include using namespace std; int main()  ifstream ifile("test.txt", ios::in); if (ifile.is_open())  string line; getline(ifile, line); cout  <line  <end; > return 0; > 

Наконец, для чтения символов из потока по одному можно использовать метод get()

char c; while (ifile.get(c))  cout  <c; > 

Аналогичный метод есть и у объекта cin .

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

Строковые потоки

Часто бывает удобно работать со строковыми потоками. Инструменты для работы со строковыми потоками подключаются с помощью заголовочного файла . Строковые потоки позволяют удобно инициализировать объекты различных типов из их текстового представления. Представим себе, что мы получили географические координаты НГУ в виде строки «(54.847830, 83.094392)» . Наша задача извлечь из строки две величины типа double . Сделать это можно следующим образом:

#include #include #include using namespace std; int main()  string nsucoor("(54.847830, 83.094392)"); stringstream ss(nsucoor); double lat, lon; ss.ignore(1); // skip '(' ss >> lat; ss.ignore(2); // skip ", " ss >> lon; cout  <lat  <", "  <lon  <endl; return 0; > 

Резюме

Мы обсудили, что все операции ввода-вывода в С++ реализованы единообразно с помощью потоков. Вывод в поток осуществляется с помощью оператора вставки > . Мы рассмотрели три типа потоков: стандартные, файловые и строковые. Этого достаточно для уверенного начала работы с потоками ввода-вывода в C++.

Документация

Источник

Оцените статью