Файл: А. В. Гордеев А. Ю. Молчанов системное программное обеспечение электронный вариант книги издательства Питер СанктПетербург Челябинск юургу каф. Автоматика и управление 2002 2 Предисловие Настоящий учебник.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 12.01.2024
Просмотров: 1033
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Реализация функций API с помощью внешних библиотек
При реализации функций API с помощью внешних библиотек они предостав- ляются пользователю в виде библиотеки процедур и функций, созданной сторон- ним разработчиком. Причем разработчиком такой библиотеки может выступать тот же самый производитель.
Система программирования ответственна только за то, чтобы подключить объектный код библиотеки к результирующей программе. Причем внешняя биб- лиотека может быть и динамически загружаемой (загружаемой во время выполне- ния программы).
С точки зрения эффективности выполнения этот метод реализации API имеет самые низкие результаты, поскольку внешняя библиотека обращается как к функ- циям ОС, так и к функциям RTL языка программирования. Только при очень высо- ком качестве внешней библиотеки её эффективность становится сравнимой с биб- лиотекой RTL.
Если говорить о переносимости исходного кода, то здесь требование только одно – используемая внешняя библиотека должна быть доступна в любой из архи- тектур вычислительных систем, на которые ориентирована прикладная программа.
Тогда удаётся достигнуть переносимости. Это возможно, если используемая биб- лиотека удовлетворяет какому-то принятому стандарту, а система программирова- ния поддерживает этот стандарт.
Например, библиотеки, удовлетворяющие стандарту POSIX (см. следующий подраздел), доступны в большинстве систем программирования для языка С. И ес- ли прикладная программа использует только библиотеки этого стандарта, то ее ис- ходный код будет переносимым. Еще одним примером является широко известная библиотека графического интерфейса XLib, поддерживающая стандарт графиче- ской среды Х Window.
267
Для большинства специфических библиотек отдельных разработчиков это не так. Если пользователь использует какую-то библиотеку, то она ориентирована на ограниченный набор доступных архитектур целевой вычислительной системы.
Примерами могут служить библиотеки MFC (Microsoft foundation classes) фирмы
Microsoft и VCL (visual controls library) фирмы Borland, жёстко ориентированные на архитектуруОС типа Windows. Тем не менее, многие фирмы-разработчики сей- час стремятся создать библиотеки, которые бы обеспечивали переносимость ис- ходного кода приложений между различными архитектурами целевой вычисли- тельной системы. Пока ещё такие библиотеки не получили широкого распростра- нения, но есть несколько попыток их реализации – например, библиотека CLX
производства фирмы Borland ориентирована на архитектуру ОС типа Linux и ОС
типа Windows.
В целом развитие функций прикладного API идет в направлении попытки соз- дать библиотеки API, обеспечивающие широкую переносимость исходного кода.
Однако, учитывая корпоративные интересы различных производителей и сложив- шуюся ситуацию на рынке системного программного обеспечения, в ближайшее время вряд ли удастся достичь значительных успехов в этом направлении. Разра- ботка широко применимого стандарта API пока ещё остается делом будущего.
Поэтому разработчики системных программ вынуждены оставаться в доволь- но узких рамках ограничений стандартных библиотек языков программирования.
Что касается прикладных программ, то гораздо большую перспективу для них предоставляют технологии, связанные с разработками в рамках архитектуры «кли- ент–сервер» или трехуровневой архитектуры создания приложений. В этом на- правлении ведущие производители ОС, СУБД и систем программирования скорее достигнут соглашений, чем в направлении стандартизации API.
Итак, нами были рассмотрены основные принципы, цели и подходы к реали- зации системных API. Отметим ещё один очень важный момент: желательно, что–
бы интерфейс прикладного программирования не зависел от системы программиро- вания. Конечно, были одно время персональные компьютеры, у которых базовой системой программирования выступал интерпретатор с языка Basic, но это скорее
268
исключение. Обычно базовые функции API не зависят от системы программирова- ния и могут использоваться из любой системы программирования, хотя и с приме- нением соответствующих правил построения вызывающих последовательностей. В
то же время в ряде случаев система программирования может сама генерировать обращения к функциям API. Например, мы можем написать в программе вызов функции по запросу 256 байт памяти unsigned char * ptr = malloc (256);
Система программирования языка С сгенерирует целую последовательность обращений. Из кода пользовательской программы будет осуществлен вызов биб- лиотечной функции malloc, код которой расположен в RTL языка С. Библиотека времени выполнения в данном случае реализует вызов mallос уже как вызов сис- темной функции API HeapAlloc
LPVOID НеарАllос{
HANDLE hHeap, // handle to the private heap block – указатель на блок
DWORD dwFlags, //heap allocation control flags – свойства блока
DWORD dwBytes // number of bytes to allocate – размер блока
};
Параметры выделяемого блока памяти в таком случае задаются системой про- граммирования, и пользователь лишён возможности задавать их напрямую. С дру- гой стороны, если это необходимо, возможно использование функций API прямо в тексте программы.
unsigned char * ptr = (LPVOID) НеарАllос( GetProcessHeap(), 0, 256);
В этом случае программирование вызова немного усложняется, но получае- мый конечный результат будет, как правило, короче и, что самое важное, будет ра- ботать эффективнее. Следует отметить, что далеко не все возможности API дос- тупны через обращения к функциям системы программирования. Непосредствен- ное обращение к функциям API позволяет пользователю обращаться к системным ресурсам более эффективным способом. Однако это требует знания функций API,
количество которых нередко достигает нескольких сотен.
269
Как правило, API не стандартизированы. В каждом конкретном случае набор вызовов API определяется, прежде всего, архитектурой ОС и её назначением. В то же время принимаются попытки стандартизировать некоторый базовый набор функций, поскольку это существенно облегчает перенос приложений с одной ОС в другую. Таким примером может служить очень известный и, пожалуй, один из са- мых распространенных стандартов – стандарт POSIX. В этом стандарте перечислен большой набор функций, их параметров и возвращаемых значений. Стандартизи- рованными, согласно POSIX, являются не только обращения к API, но и файловая система, организация доступа к внешним устройствам, набор системных команд
1
Использование в приложениях этого стандарта позволяет в дальнейшем легко пе- реносить такие программы с одной ОС в другую путем простейшей перекомпиля- ции исходного текста.
Частным случаем попытки стандартизации API является внутренний корпора- тивный стандарт компании Microsoft, известный как WinAPI. Он включает в себя следующие реализации: Win 16, Win32s, Win32, WinCE. С точки зрения WinAPI (в силу ряда идеологических причин – обязательный графический «оконный» интер- фейс пользователя), базовой задачей является окно. Таким образом, WinAPI изна- чально ориентирован на работу в графической среде. Однако базовые понятия до- полнены традиционными функциями, в том числе частично поддерживается стан- дарт POSIX.
Платформенно-независимый интерфейс POSIX
POSIX (Portable Operating System Interface for Computer Environments) – плат- форменно независимый системный интерфейс для компьютерного окружения. Это стандарт IEEE, описывающий системные интерфейсы для открытых операционных систем, в том числе оболочки, утилиты и инструментарии. Помимо этого, согласно
POSIX, стандартизированными являются задачи обеспечения безопасности, задачи реального времени, процессы администрирования, сетевые функции и обработка транзакций. Стандарт базируется на UNIX-системах, но допускает реализацию и в других ОС.
1
В данном контексте под системными командами следует понимать некий набор программ, позволяющих управлять вычислительными процессами. Например, pstat, kill, dir и др.
270
POSIX возник как попытка всемирно известной организации IEEE
2
пропаган- дировать переносимость приложений в UNIX-средах путём разработки абстрактно- го, платформенно-независимого стандарта. Однако POSIX не ограничивается толь- ко UNIX-системами; существуют различные реализации этого стандарта в систе- мах, которые соответствуют требованиям, предъявляемым стандартом IEEE Stan- dard 1003.1-1990 (POSIX.1). Например, известная ОС реального времени QNX со- ответствует спецификациям этого стандарта, что облегчает перенос приложений в эту систему, но UNIX-системой не является ни в каком виде, ибо её архитектура использует абсолютно иные принципы.
Этот стандарт подробно описывает VMS (virtual memory system, систему вир- туальной памяти), многозадачность (МРЕ, multiprocess executing) и технологию пе- реноса операционных систем (CTOS). Таким образом, на самом деле POSIX пред- ставляет собой множество стандартов, именуемых POSIX.1 – POSIX.12.
Таблица 5.1. Семейство стандартов POSIX
Стандарт Стандарт ISO Краткое описание
POSIX.0
Нет
Введение в стандарт открытых систем. Данный документ не является
стандартом в чистом виде, а представляет собой рекомендации и
краткий обзор технологий
POSIX.1
Да
Системный API (язык С)
POSIX.2
Нет
Оболочки и утилиты (одобренные IEEE)
POSIX.3
Нет
Тестирование и верификация
POSIX.4
Нет
Задачи реального времени и нити
POSIX.5
Да
Использование языка ADA применительно к стандарту POSIX.1
POSIX.6
Нет
Системная безопасность
POSIX.7
Нет
Администрирование системы
POSIX.8
Нет
Сети
«Прозрачный» доступ к файлам
Абстрактные сетевые интерфейсы, не зависящие от физических
протоколов
RPC (remote procedure calls, вызовы удаленных процедур)
POSIX.9
Да
Использование языка FORTRAN применительно к стандарту POSIX. 1
POSIX.10
Нет
Super-computing Application Environment Profile (AEP)
POSIX.11
Нет
Обработка транзакций АЕР
POSIX. 12
Нет
Графический интерфейс пользователя (GUI)
2
IEEE (Institute of Electrical and Electronical Engineers) – американский Институт инженеров по электротехнике и радиоэлектронике.
271
В табл. 5.1 приведены основные направления, описываемые данными стандар- тами. Следует также особо отметить, что POSIX.1 предполагает язык С как основ- ной язык описания системных функций API.
Таким образом, программы, написанные с соблюдением данных стандартов,
будут одинаково выполняться на всех POSIX-совместимых системах. Однако стан- дарт в некоторых случаях носит лишь рекомендательный характер. Часть стандар- тов описана очень строго, тогда как другая часть только поверхностно раскрывает основные требования. Нередко программные системы заявляются как POSIX–со- вместимые, хотя таковыми их назвать нельзя. Причины кроются в формальности подхода к реализации POSIX-интерфейса в различных ОС. На рис. 5.1 изображена типовая схема реализации строго соответствующего POSIX приложения.
Рис.5.1. Приложения, строго соответствующие стандарту POSIX
Из рис.5.1 видно, что для взаимодействия с операционной системой програм- ма использует только библиотеки POSIX.1 и стандартную библиотеку RTL языка
С, в которой возможно использование лишь 110 различных функций, также опи- санных стандартом POSIX.1.
272
К сожалению, достаточно часто с целью увеличить производительность той или иной подсистемы либо из соображений введения фирменных технологий, ко- торые ограничивают использование приложения соответствующей операционной,
средой, при программировании используются другие функции, не отвечающие стандарту POSIX.
Реализации POSIX API на уровне операционной системы различны. Если
UNIX-системы в своём абсолютном большинстве изначально соответствуют спе- цификациям IEEE Standard 1003.1-1990, то WinAPI не является POSIX–совмести- мым. Однако для поддержки данного стандарта в операционной системе MS Win- dows NT введен специальный модуль поддержки POSIX API, работающий на уров- не привилегий пользовательских процессов. Данный модуль обеспечивает конвер- тацию и передачу вызовов из пользовательской программы к ядру системы и об- ратно, работая с ядром через WinAPI. Прочие, приложения, написанные с исполь- зованием WinAPI, могут передавать информацию POSIX-приложениям через стан- дартные механизмы потоков ввода/вывода (stdin, stdout) [97].
Пример программирования в различных API ОС
Для наглядной демонстрации принципиальных различий API наиболее попу- лярных современных операционных систем для ПК рассмотрим простейший при- мер, в котором реализуется следующая задача.
Постановка задачи: необходимо подсчитать количество пробелов в текстовых файлах, имена которых должны указываться в командной строке. Рассмотрим два варианта программы, решающей эту задачу, – для Windows (с использованием
WinAPI) и для Linux (POSIX API).
Поскольку нас интересует работа с параллельными задачами, пусть при вы- полнении программы для каждого перечисленного в командной строке файла соз- даётся свой процесс или задача (тред), который параллельно с другими процессами
(тредами) производит работу по подсчёту пробелов в «своём» файле. Результатом работы программы будет являться список файлов с подсчитанным количеством пробелов для каждого.
273
Следует обратить особое внимание на то, что приведенная ниже конкретная реализация данной задачи не является единственно возможной. В обеих рассмат- риваемых операционных системах существуют различные методы как работы с файловой системой, так и управления процессами. В данном случае рассматрива- ется только один, но наиболее характерный для соответствующего API вариант.
Текст программы для Windows (WinAPI)
Для того чтобы было удобнее сравнивать эту и следующую программы, а так- же, из-за того, что настоящая задача не требует для своего решения оконного ин- терфейса, в нижеприведённом тексте использованы только те вызовы API, которые не затрагивают графический интерфейс. Конечно, нынче редко какое приложение не использует возможностей GUI, но в нашем случае зато сразу можно увидеть разницу в организации параллельной работы запускаемых вычислений.
#include
#include
#include
// Название: processFile
// Описание: исполняемый код треда
// Входные параметры: lpFileName – имя файла для обработки
// Выходные параметры: нет
//
DWORD processFile(LPVOID IpFileName)
{
HANDLE handle; // описатель файла
DWORD numRead, total = 0;
char buf;
// запрос к ОС на открытие файла (только для чтения)
handle = CreateFile( (LPCTSTR)lpFileName, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// цикл чтения до конца файла do {
// чтение одного символа из файла
ReadFile( handle, (LPVOID) &buf, 1, &numRead, NULL);
if (buf == 0х20) total++;
} while ( numRead > 0);
fprintf( stderr, "(ThreadID: %Lu), File %s, spaces = %d\n",
GetCurrentThreadId(), IpFileName, total);
// закрытие файла
CloseHandle( handle);
return(0);
}
// Название: main
// Описание: главная программа
// Входные параметры: список имён файлов для обработки
274
// Выходные параметры: нет
//
int main(int argc, char *argv[ ])
{
int i;
DWORD pid;
HANDLE hThrd[255]; // массив ссылок на треды
// для всех файлов, перечисленных в командной строке for (i = 0; i< (argc-1); i++)
{
// запуск треда – обработка одного файла hThrd[i] = CreateThread( NULL, 0х4000,
(LPTHREAD_START_ROUTINE) processFile, (LPVOID) argv[i+1], 0, &pid);
fprintf( stdout, "processFile started (HND=%d)\n", hThrd[i]);
}
// ожидание окончания выполнения всех запущенных тредов
WaitForMultipleObjects( argc-1, hThrd, true, INFINITE);
return(0);
}
Обратите внимание, что основная программа запускает треды и ждёт оконча- ния их выполнения.
Текст программы для Linux (POSIX API)
#include
#include
#include
#include
#include
// Название: processFile
//Описание: обработка файла, подсчет кол-ва пробелов
// Входные параметры: fileName – имя файла для обработки
// Выходные параметры: кол-во пробелов в файле
//
int processFile( char *fileName)
{
nt handle, numRead, total = 0;
char buf;
// запрос к ОС на открытие файла (только для чтения)
handle = open( fileName, O_RDONLY);
// цикл чтения до конца файла do
{
// чтение одного символа из файла numRead = read( handle, &buf, 1);
if (buf = 0х20) total++;
} while (numRead > 0);
// закрытие файла close( handle);
return( total);
}
// Название: main
При реализации функций API с помощью внешних библиотек они предостав- ляются пользователю в виде библиотеки процедур и функций, созданной сторон- ним разработчиком. Причем разработчиком такой библиотеки может выступать тот же самый производитель.
Система программирования ответственна только за то, чтобы подключить объектный код библиотеки к результирующей программе. Причем внешняя биб- лиотека может быть и динамически загружаемой (загружаемой во время выполне- ния программы).
С точки зрения эффективности выполнения этот метод реализации API имеет самые низкие результаты, поскольку внешняя библиотека обращается как к функ- циям ОС, так и к функциям RTL языка программирования. Только при очень высо- ком качестве внешней библиотеки её эффективность становится сравнимой с биб- лиотекой RTL.
Если говорить о переносимости исходного кода, то здесь требование только одно – используемая внешняя библиотека должна быть доступна в любой из архи- тектур вычислительных систем, на которые ориентирована прикладная программа.
Тогда удаётся достигнуть переносимости. Это возможно, если используемая биб- лиотека удовлетворяет какому-то принятому стандарту, а система программирова- ния поддерживает этот стандарт.
Например, библиотеки, удовлетворяющие стандарту POSIX (см. следующий подраздел), доступны в большинстве систем программирования для языка С. И ес- ли прикладная программа использует только библиотеки этого стандарта, то ее ис- ходный код будет переносимым. Еще одним примером является широко известная библиотека графического интерфейса XLib, поддерживающая стандарт графиче- ской среды Х Window.
267
Для большинства специфических библиотек отдельных разработчиков это не так. Если пользователь использует какую-то библиотеку, то она ориентирована на ограниченный набор доступных архитектур целевой вычислительной системы.
Примерами могут служить библиотеки MFC (Microsoft foundation classes) фирмы
Microsoft и VCL (visual controls library) фирмы Borland, жёстко ориентированные на архитектуруОС типа Windows. Тем не менее, многие фирмы-разработчики сей- час стремятся создать библиотеки, которые бы обеспечивали переносимость ис- ходного кода приложений между различными архитектурами целевой вычисли- тельной системы. Пока ещё такие библиотеки не получили широкого распростра- нения, но есть несколько попыток их реализации – например, библиотека CLX
производства фирмы Borland ориентирована на архитектуру ОС типа Linux и ОС
типа Windows.
В целом развитие функций прикладного API идет в направлении попытки соз- дать библиотеки API, обеспечивающие широкую переносимость исходного кода.
Однако, учитывая корпоративные интересы различных производителей и сложив- шуюся ситуацию на рынке системного программного обеспечения, в ближайшее время вряд ли удастся достичь значительных успехов в этом направлении. Разра- ботка широко применимого стандарта API пока ещё остается делом будущего.
Поэтому разработчики системных программ вынуждены оставаться в доволь- но узких рамках ограничений стандартных библиотек языков программирования.
Что касается прикладных программ, то гораздо большую перспективу для них предоставляют технологии, связанные с разработками в рамках архитектуры «кли- ент–сервер» или трехуровневой архитектуры создания приложений. В этом на- правлении ведущие производители ОС, СУБД и систем программирования скорее достигнут соглашений, чем в направлении стандартизации API.
Итак, нами были рассмотрены основные принципы, цели и подходы к реали- зации системных API. Отметим ещё один очень важный момент: желательно, что–
бы интерфейс прикладного программирования не зависел от системы программиро- вания. Конечно, были одно время персональные компьютеры, у которых базовой системой программирования выступал интерпретатор с языка Basic, но это скорее
268
исключение. Обычно базовые функции API не зависят от системы программирова- ния и могут использоваться из любой системы программирования, хотя и с приме- нением соответствующих правил построения вызывающих последовательностей. В
то же время в ряде случаев система программирования может сама генерировать обращения к функциям API. Например, мы можем написать в программе вызов функции по запросу 256 байт памяти unsigned char * ptr = malloc (256);
Система программирования языка С сгенерирует целую последовательность обращений. Из кода пользовательской программы будет осуществлен вызов биб- лиотечной функции malloc, код которой расположен в RTL языка С. Библиотека времени выполнения в данном случае реализует вызов mallос уже как вызов сис- темной функции API HeapAlloc
LPVOID НеарАllос{
HANDLE hHeap, // handle to the private heap block – указатель на блок
DWORD dwFlags, //heap allocation control flags – свойства блока
DWORD dwBytes // number of bytes to allocate – размер блока
};
Параметры выделяемого блока памяти в таком случае задаются системой про- граммирования, и пользователь лишён возможности задавать их напрямую. С дру- гой стороны, если это необходимо, возможно использование функций API прямо в тексте программы.
unsigned char * ptr = (LPVOID) НеарАllос( GetProcessHeap(), 0, 256);
В этом случае программирование вызова немного усложняется, но получае- мый конечный результат будет, как правило, короче и, что самое важное, будет ра- ботать эффективнее. Следует отметить, что далеко не все возможности API дос- тупны через обращения к функциям системы программирования. Непосредствен- ное обращение к функциям API позволяет пользователю обращаться к системным ресурсам более эффективным способом. Однако это требует знания функций API,
количество которых нередко достигает нескольких сотен.
269
Как правило, API не стандартизированы. В каждом конкретном случае набор вызовов API определяется, прежде всего, архитектурой ОС и её назначением. В то же время принимаются попытки стандартизировать некоторый базовый набор функций, поскольку это существенно облегчает перенос приложений с одной ОС в другую. Таким примером может служить очень известный и, пожалуй, один из са- мых распространенных стандартов – стандарт POSIX. В этом стандарте перечислен большой набор функций, их параметров и возвращаемых значений. Стандартизи- рованными, согласно POSIX, являются не только обращения к API, но и файловая система, организация доступа к внешним устройствам, набор системных команд
1
Использование в приложениях этого стандарта позволяет в дальнейшем легко пе- реносить такие программы с одной ОС в другую путем простейшей перекомпиля- ции исходного текста.
Частным случаем попытки стандартизации API является внутренний корпора- тивный стандарт компании Microsoft, известный как WinAPI. Он включает в себя следующие реализации: Win 16, Win32s, Win32, WinCE. С точки зрения WinAPI (в силу ряда идеологических причин – обязательный графический «оконный» интер- фейс пользователя), базовой задачей является окно. Таким образом, WinAPI изна- чально ориентирован на работу в графической среде. Однако базовые понятия до- полнены традиционными функциями, в том числе частично поддерживается стан- дарт POSIX.
Платформенно-независимый интерфейс POSIX
POSIX (Portable Operating System Interface for Computer Environments) – плат- форменно независимый системный интерфейс для компьютерного окружения. Это стандарт IEEE, описывающий системные интерфейсы для открытых операционных систем, в том числе оболочки, утилиты и инструментарии. Помимо этого, согласно
POSIX, стандартизированными являются задачи обеспечения безопасности, задачи реального времени, процессы администрирования, сетевые функции и обработка транзакций. Стандарт базируется на UNIX-системах, но допускает реализацию и в других ОС.
1
В данном контексте под системными командами следует понимать некий набор программ, позволяющих управлять вычислительными процессами. Например, pstat, kill, dir и др.
270
POSIX возник как попытка всемирно известной организации IEEE
2
пропаган- дировать переносимость приложений в UNIX-средах путём разработки абстрактно- го, платформенно-независимого стандарта. Однако POSIX не ограничивается толь- ко UNIX-системами; существуют различные реализации этого стандарта в систе- мах, которые соответствуют требованиям, предъявляемым стандартом IEEE Stan- dard 1003.1-1990 (POSIX.1). Например, известная ОС реального времени QNX со- ответствует спецификациям этого стандарта, что облегчает перенос приложений в эту систему, но UNIX-системой не является ни в каком виде, ибо её архитектура использует абсолютно иные принципы.
Этот стандарт подробно описывает VMS (virtual memory system, систему вир- туальной памяти), многозадачность (МРЕ, multiprocess executing) и технологию пе- реноса операционных систем (CTOS). Таким образом, на самом деле POSIX пред- ставляет собой множество стандартов, именуемых POSIX.1 – POSIX.12.
Таблица 5.1. Семейство стандартов POSIX
Стандарт Стандарт ISO Краткое описание
POSIX.0
Нет
Введение в стандарт открытых систем. Данный документ не является
стандартом в чистом виде, а представляет собой рекомендации и
краткий обзор технологий
POSIX.1
Да
Системный API (язык С)
POSIX.2
Нет
Оболочки и утилиты (одобренные IEEE)
POSIX.3
Нет
Тестирование и верификация
POSIX.4
Нет
Задачи реального времени и нити
POSIX.5
Да
Использование языка ADA применительно к стандарту POSIX.1
POSIX.6
Нет
Системная безопасность
POSIX.7
Нет
Администрирование системы
POSIX.8
Нет
Сети
«Прозрачный» доступ к файлам
Абстрактные сетевые интерфейсы, не зависящие от физических
протоколов
RPC (remote procedure calls, вызовы удаленных процедур)
POSIX.9
Да
Использование языка FORTRAN применительно к стандарту POSIX. 1
POSIX.10
Нет
Super-computing Application Environment Profile (AEP)
POSIX.11
Нет
Обработка транзакций АЕР
POSIX. 12
Нет
Графический интерфейс пользователя (GUI)
2
IEEE (Institute of Electrical and Electronical Engineers) – американский Институт инженеров по электротехнике и радиоэлектронике.
271
В табл. 5.1 приведены основные направления, описываемые данными стандар- тами. Следует также особо отметить, что POSIX.1 предполагает язык С как основ- ной язык описания системных функций API.
Таким образом, программы, написанные с соблюдением данных стандартов,
будут одинаково выполняться на всех POSIX-совместимых системах. Однако стан- дарт в некоторых случаях носит лишь рекомендательный характер. Часть стандар- тов описана очень строго, тогда как другая часть только поверхностно раскрывает основные требования. Нередко программные системы заявляются как POSIX–со- вместимые, хотя таковыми их назвать нельзя. Причины кроются в формальности подхода к реализации POSIX-интерфейса в различных ОС. На рис. 5.1 изображена типовая схема реализации строго соответствующего POSIX приложения.
Рис.5.1. Приложения, строго соответствующие стандарту POSIX
Из рис.5.1 видно, что для взаимодействия с операционной системой програм- ма использует только библиотеки POSIX.1 и стандартную библиотеку RTL языка
С, в которой возможно использование лишь 110 различных функций, также опи- санных стандартом POSIX.1.
272
К сожалению, достаточно часто с целью увеличить производительность той или иной подсистемы либо из соображений введения фирменных технологий, ко- торые ограничивают использование приложения соответствующей операционной,
средой, при программировании используются другие функции, не отвечающие стандарту POSIX.
Реализации POSIX API на уровне операционной системы различны. Если
UNIX-системы в своём абсолютном большинстве изначально соответствуют спе- цификациям IEEE Standard 1003.1-1990, то WinAPI не является POSIX–совмести- мым. Однако для поддержки данного стандарта в операционной системе MS Win- dows NT введен специальный модуль поддержки POSIX API, работающий на уров- не привилегий пользовательских процессов. Данный модуль обеспечивает конвер- тацию и передачу вызовов из пользовательской программы к ядру системы и об- ратно, работая с ядром через WinAPI. Прочие, приложения, написанные с исполь- зованием WinAPI, могут передавать информацию POSIX-приложениям через стан- дартные механизмы потоков ввода/вывода (stdin, stdout) [97].
Пример программирования в различных API ОС
Для наглядной демонстрации принципиальных различий API наиболее попу- лярных современных операционных систем для ПК рассмотрим простейший при- мер, в котором реализуется следующая задача.
Постановка задачи: необходимо подсчитать количество пробелов в текстовых файлах, имена которых должны указываться в командной строке. Рассмотрим два варианта программы, решающей эту задачу, – для Windows (с использованием
WinAPI) и для Linux (POSIX API).
Поскольку нас интересует работа с параллельными задачами, пусть при вы- полнении программы для каждого перечисленного в командной строке файла соз- даётся свой процесс или задача (тред), который параллельно с другими процессами
(тредами) производит работу по подсчёту пробелов в «своём» файле. Результатом работы программы будет являться список файлов с подсчитанным количеством пробелов для каждого.
273
Следует обратить особое внимание на то, что приведенная ниже конкретная реализация данной задачи не является единственно возможной. В обеих рассмат- риваемых операционных системах существуют различные методы как работы с файловой системой, так и управления процессами. В данном случае рассматрива- ется только один, но наиболее характерный для соответствующего API вариант.
Текст программы для Windows (WinAPI)
Для того чтобы было удобнее сравнивать эту и следующую программы, а так- же, из-за того, что настоящая задача не требует для своего решения оконного ин- терфейса, в нижеприведённом тексте использованы только те вызовы API, которые не затрагивают графический интерфейс. Конечно, нынче редко какое приложение не использует возможностей GUI, но в нашем случае зато сразу можно увидеть разницу в организации параллельной работы запускаемых вычислений.
#include
#include
#include
// Название: processFile
// Описание: исполняемый код треда
// Входные параметры: lpFileName – имя файла для обработки
// Выходные параметры: нет
//
DWORD processFile(LPVOID IpFileName)
{
HANDLE handle; // описатель файла
DWORD numRead, total = 0;
char buf;
// запрос к ОС на открытие файла (только для чтения)
handle = CreateFile( (LPCTSTR)lpFileName, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// цикл чтения до конца файла do {
// чтение одного символа из файла
ReadFile( handle, (LPVOID) &buf, 1, &numRead, NULL);
if (buf == 0х20) total++;
} while ( numRead > 0);
fprintf( stderr, "(ThreadID: %Lu), File %s, spaces = %d\n",
GetCurrentThreadId(), IpFileName, total);
// закрытие файла
CloseHandle( handle);
return(0);
}
// Название: main
// Описание: главная программа
// Входные параметры: список имён файлов для обработки
274
// Выходные параметры: нет
//
int main(int argc, char *argv[ ])
{
int i;
DWORD pid;
HANDLE hThrd[255]; // массив ссылок на треды
// для всех файлов, перечисленных в командной строке for (i = 0; i< (argc-1); i++)
{
// запуск треда – обработка одного файла hThrd[i] = CreateThread( NULL, 0х4000,
(LPTHREAD_START_ROUTINE) processFile, (LPVOID) argv[i+1], 0, &pid);
fprintf( stdout, "processFile started (HND=%d)\n", hThrd[i]);
}
// ожидание окончания выполнения всех запущенных тредов
WaitForMultipleObjects( argc-1, hThrd, true, INFINITE);
return(0);
}
Обратите внимание, что основная программа запускает треды и ждёт оконча- ния их выполнения.
Текст программы для Linux (POSIX API)
#include
#include
#include
#include
#include
// Название: processFile
//Описание: обработка файла, подсчет кол-ва пробелов
// Входные параметры: fileName – имя файла для обработки
// Выходные параметры: кол-во пробелов в файле
//
int processFile( char *fileName)
{
nt handle, numRead, total = 0;
char buf;
// запрос к ОС на открытие файла (только для чтения)
handle = open( fileName, O_RDONLY);
// цикл чтения до конца файла do
{
// чтение одного символа из файла numRead = read( handle, &buf, 1);
if (buf = 0х20) total++;
} while (numRead > 0);
// закрытие файла close( handle);
return( total);
}
// Название: main