Автор: Пользователь скрыл имя, 20 Января 2011 в 12:43, лекция
Несмотря на тот факт, что в наши дни уже практически никто не разрабатыва¬ет операционные системы (естественно, за исключением нескольких известных компаний, специализирующихся на этом направлении, кстати, одном из слож¬нейших) и все являются пользователями наиболее распространенных систем, мы все-таки рассмотрим кратко вопросы архитектуры ОС. Сделать это необхо¬димо потому, что многие возможности и характеристики ОС определяются в значительной мере ее архитектурой.
Поскольку нас интересует работа с параллельными задачами, пусть при выполнении программы для каждого перечисленного в командной строке файла создается свой процесс или задача (тред), который параллельно с другими процессами (тредами) производит работу по подсчету пробелов в «своем» файле. Результатом работы программы будет являться список файлов с подсчитанным количеством пробелов для каждого.
Следует обратить особое внимание на то, что приведенная ниже конкретная реализация данной задачи не является единственно возможной. В обеих рассматриваемых операционных системах существуют различные методы как работы с файловой системой, так и управления процессами. В данном случае рассматривается только один, но наиболее характерный для соответствующего API вариант.
Текст программы для Windows (WinAPI)
Для того чтобы было удобнее сравнивать эту и следующую программы, а также из-за того, что настоящая задача не требует для своего решения оконного интерфейса, в нижеприведенном тексте использованы только те вызовы API, которые не затрагивают графический интерфейс. Конечно, нынче редко какое приложение не использует возможностей GUI, но в нашем случае зато сразу можно увидеть разницу в организации параллельной работы запускаемых вычислений.
#include <windows.h>
#include <stdio.h> >
#include <stdlib.h>
// Название
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 == 0x20) total++ } while ( numRead > 0):
fprintf(stderr, "(ThreadID %Lu), File %s spaces = %d\n", GetCurrentThreadId(), lpFileName, total);
// закрытие файла CloseHandle( handle).
return(0) }
// Название main
// Описание главная программа
// Входные параметры
список имен файлов для
// Выходные параметры нет
//
int main(int argc, char *argv[]) {
int i;
DWORD pid;
HANDLE hThrd[255]; // массив ссылок на треды
// для всех файлов, перечисленных в командной строке for (i = 0, i< (argc-1), i++) {
// запуск треда - обработка одного файла hThrd[i] = CreateThread( NULL, 0x4000, (LPTHREAD_START_ROUTINE) processFile,
(LPVOID) argv[i+l], 0, &pid);
fprintf(stdout, "processFile started (HND=%d)\n", hThrd[i]); }
// ожидание окончания
выполнения всех запущенных
WaitForMu1tipleObjects( argc-1, hThrd, true, INFINITE);
return(0); }
Обратите внимание, чтo основная программа запускает треды и ждет окончания их выполнения.
Текст программы для Linux (POSIX API)
#include <sys/types.h> #include <sys/stat.h>
#include <wait.h> #include <fcntl.h> #include <stdio.h>
// Название: processFile
// Описание: обработка файла, подсчет кол-ва пробелов
// Входные параметры: fileName - имя файла для обработки
// Выходные параметры: кол-во пробелов в файле
//
int processFile( char *fileName) {
int handleб numRead, total = 0;
char buf;
// запрос к ОС на открытие файла (
только для чтения) handle = open( fileName, 0_RDONLY);
// цикл чтения до конца файла do {
// чтение одного символа из файла
numRead = read( handle, &buf, 1);
if (buf == 0x20) total++; } while (numRead > 0);
// закрытие файла close(handle): return(total); }
// для всех файлов, перечисленных в командной строке for (i = 1, i< argc, i++) { // запускаем дочерний процесс pid = fork(), if (pid == 0) {
// если выполняется дочерний процесс // вызов функции счета
количества пробелов в файле
pnntf( "(PID: %d), File %s, spaces = %d\n", getpid(), argv[i],
processFile( argv[i]));
// выход из процесса exit();
}
// если выполняется родительский
процесс else
pnntf("processFile started (pid=%d)\n", pid); }
// ожидание окончания
выполнения всех запущенных
if (pid != 0) while (wait(&status)>0);
return; }
// Название: main
// Описание: главная программа
// Входные параметры:
список имен файлов для
// Выходные параметры: нет
//
int main(int argc. char *argv[]) { int i, pid, status;
Из этого текста видно, что в этом случае все вычисления принимают статус процессов, а не тредов.
В заключение можно заметить, что очень трудно сравнивать API. При их разработке создатели, как правило, стараются реализовать полный набор основных функций, используя которые можно решать различные задачи, хотя, порой, и различными способами. Один набор будет хорош для одного набора задач, другой — для иного набора задач. Тем более что фактически у нас сейчас существенно ограниченное множество API. Причина в том, что доминируют наиболее распространенные ОС, на распространение которых в большей степени оказали влияние не достоинства или недостатки этих ОС и их API, а правильная маркетинговая политика фирм, их создавших.
Информация о работе Архитектура операционных систем и интерфейсы прикладного программирования