- •1.Архитектура операционных систем
- •1.1Общие вопросы архитектуры операционных систем
- •1.2Архитектура Windows
- •1.2.1История возникновения Windows
- •1.2.2Архитектура ос Windows
- •1.2.3История возникновения ос Linux
- •1.2.4Архитектура Linux
- •1.2.5Интерфейсы системы unix
- •1.2.6Файловая система unix
- •1.2.7Аутентификация в unix
- •1.2.8Сценарии командной оболочки unix
- •1.3Операционная система qnx
- •1.3.1 Архитектура qnx
- •1.4Выводы
- •1.5Вопросы для самоконтроля
- •2.Типы и алгоритмы работы с оперативной памятью
- •2.1Общие принципы функционирования подсистемы памяти в ос
- •2.1.1Обобщённые принципы управления памятью
- •2.1.2Однозадачная система без подкачки на диск
- •2.1.3Многозадачность с фиксированными разделами
- •2.1.4Подкачка
- •2.1.5Управление памятью с помощью битовых массивов
- •2.1.6Управление памятью с помощью связанных списков
- •2.1.7Виртуальная память
- •2.1.8Многоуровневые таблицы страниц
- •2.1.9Алгоритмы замещения страниц
- •2.2Виртуальная память ос Windows
- •2.2.1Архитектура памяти в ос Windows
- •2.2.2Работа с виртуальной памятью в ос Windows
- •2.2.3Использование виртуальной памяти в приложениях
- •2.3Пример организации страничной памяти на примере linux
- •2.3.1Страничная организация памяти в Linux
- •2.3.2Права доступа к области памяти
- •2.3.3Работа с областями памяти в Linux
- •3.Процессы и потоки
- •3.1Процессы
- •3.1.1Модель процесса
- •3.1.2Создание процесса
- •3.1.3Завершение процесса
- •3.1.4Состояния процессов
- •3.1.5Реализация процессов
- •3.2Потоки
- •3.2.1Реализация потоков
- •3.2.2Реализация потоков на уровне ядра
- •3.2.3Смешанная реализация
- •3.2.4 Метод управления «Активация планировщика»
- •3.2.5Всплывающие потоки
- •3.3Межпроцессное взаимодействие
- •3.3.1Состояние состязания
- •3.3.2Критические секции (Критические области)
- •3.3.3Взаимное исключение с активным ожиданием
- •3.3.4Примитивы межпроцессного взаимодействия
- •3.4Семафоры
- •3.5Мьютексы
- •3.6Организация многопоточной обработки в среде Windows
- •3.6.1Объекты ядра Windows
- •3.6.2Потоки Windows
- •3.6.3Синхронизация потоков в Windows
- •3.6.4Синхронизация потоков с помощью объектов ядра
- •3.6.5Сравнение объектов, используемых для синхронизации потоков
- •3.7Организация процессов и потоков в Linux
- •3.7.1Среда окружения в Linux
- •3.7.2Создание нового процесса. Системный вызов exec.
- •3.7.3Потоки unix. Функции потоков стандарта posix.
- •3.8Синхронизация потоков в unix
- •3.8.1Мьютексы
- •3.8.2Семафоры
- •0,0,0, //Ожидать обнуления семафора
- •0,1,0 // Затем увеличить значение семафора на 1};
- •0,1, 0 // Увеличитьзначение семафора на 1};
3.7Организация процессов и потоков в Linux
3.7.1Среда окружения в Linux
Любая UNIX-программа получает в свое распоряжение глобальную переменную environ. Она указывает на массив с переменными окружения, который также завершается пустым указателем (переменной, в которой хранилось бы количество элементов массива, не предусмотрено):
extern char **environ; /* массив переменных среды окружения */
/* (нет ни в одном из заголовочных файлов) */
Строки в массиве аргументов могут содержать любую комбинацию символов, но каждая строка обязательно завершается символом «\0». Строки с переменными окружения имеют более строгую форму. Каждая из них записывается в виде: «имя= значение», и также завершается символом «\0». Само собой разумеется, имя переменной окружения не может содержать символ «=».
Самый простой способ получения и изменения значений этого массива — обратиться к массиву environ напрямую:
extern char **environ;
int main(void) {
int i;
for (i = 0; environ[i] != NULL; i++)
printf("%s\n", environ[i]);
exit(EXIT_SUCCESS);
}
В ОС Solaris данный код вернёт следующий результат:
H0ME=/home/marc
HZ=100
LC_COLLATE=en_US.IS08859-1
LC_CTYPE=en_US.IS0BB59-1
LC_MESSAGES=C
LC_MONETARY=en_US.IS08859-1
LOGNAME=marc
MAIL=/va r/mail/marc
В целях экономии места приведен не весь список переменных. Как правило, в программах и не требуется просматривать весь список, чаще всего необходимо получить значение какой-нибудь определенной переменной. Для этой цели используется стандартная функция getenv:
#include <stdlib.h>
char *getenv
(
const char* var /* имя переменной */
);
/* Возвращает значение переменней или NULL, если таковая не найдена (значение переменней errno не определено) */
Функция getenv возвращает часть строки, которая стоит после символа «=», например, программа:
int main(void) ,
{
char *s;
s = getenv("LOGNAME");
if (s == NULL)
{
printf("переменная не найдена\п");
}
else
{
printf("значение переменней: \"Xs\"\n", s);
}
exit(EXIT_SUCCESS);
}
Данный код возвращает значение текущего имени пользователя.
Изменить значение переменной окружения не так просто, как прочитать. Хотя этот массив и является исключительной собственностью приложения и может изменяться без каких-либо ограничений, тем не менее, нет никаких гарантий, что в нем предусмотрено дополнительное место под новые строки или что в строку можно записать более длинное значение переменной. Таким образом, изменение среды окружения есть задача нетривиальная — необходимо полностью пересоздать массив строк. После этого можно будет изменить указатель environ, записав туда адрес нового массива. Измененная версия среды окружения может быть передана новым программам, запускаемым из данного приложения, к ней же будут обращаться и все последующие вызовы getenv. Изменения не коснутся других приложений, включая командный интерпретатор, который запустил процесс, выполнивший модификацию. Таким образом, если вы хотите изменить переменные окружения командной оболочки, нужно делать это с помощью самой командной оболочки.
Вместо того, чтобы работать с массивом environ напрямую, можно воспользоваться стандартными функциями putenv, setenv, unsetenv.
#include <stdlib.h>
int putenv(
char *string /* стрска e виде «имя=значение» */
);
/* Возвращает 0 в случае успеха, ненулевое значение – в случае ошибки (код ошибки - в переменной еrrпo) */
#include <stdlib.h>
int setenv(
const char *var, /* переменная, кoтoрая дoбавляется или изменяется */
const char *val, /* значение */
int overwrite /* затереть старее значение? */
);
/* Вoзвращает 0 в случае успеха, -1 в случае ошибки (код сшибки - в переменной еrrпo) */
#include <stdlib.h>
int unsetenv(
const char *var /* удаляемая переменная */
);
/* Возвращает 0 в случае успеха, -1 в случае ошибки (код сшибки – в переменной errno) */
Функции putenv и setenv изменяют илм добавляют переменные окружения, unsetenv – удаляет переменную среды окружения.
Все эти функции вносят изменения в массив, который хранит переменные среды окружения и, возможно, изменяют сам указатель environ, если в массиве обнаружится нехватка места. Если вы самостоятельно изменяете указатель environ или какую-либо часть массиве, на который он указывает, то поведение этих функций может быть непредсказуемым. Поэтому выбирайте всегда что-то одно — или вы пользуетесь стандартными функциями, или взаимодействуете со средой окружения самостоятельно, но никогда не смешивайте эти два способа.
Функция putenv принимает строку в виде «имя=значение» и вставляет в массив environ указатель на нее, в результате строка становится частью среды окружения. По этой причине никогда не передавайте функции данные с автоматическим классом размещения (локальные и нестатические переменные) и не изменяйте их содержимое после вызова putenv.
Функция setenv более сложная. Она копирует имя переменной и ее значение в специально отведенное для этого место. Если переменная уже существует, ее значение будет изменено при условии, что аргумент overwrite не равен нулю, в противном случае «старое» значение останется без изменений. Если переменной не существует, она будет добавлена в среду окружения, в этом случае значение аргумента overwrite игнорируется.
Функция unsetenv является парной к setenv. Она удаляет переменную среды окружения. Если ваша система не поддерживает функцию unsetenv, то самый лучший способ «удалить» переменную — присвоить ей в виде значения пустую строку. В некоторых случаях это может оказаться неприемлемым, но это уже зависит от самого приложения. (Некоторые системы, такие как Linux, FreeBSD и Darwin определяют unsetenv как void и в этих системах она не имеет возвращаемого значения.)
Несмотря на то, что эти функции стандартизованы, их наличие в системе не является обязательным. Операционные системы FreeBSD, Linux и Solaris имеют функцию putenv, а первые две — все три функции. Спецификация SUS3 требует наличия в системе функций setenv и unsetenv, но не все системы следуют ей. Таким образом, самый простой способ определить наличие этих функций следующий: setenv и unsetenv пришли из мира BSD, поэтому все производные системы, включая FreeBSD, поддерживают их. Функция putenv пришла из System V и должна присутствовать во всех системах, производных от System V, включая Solaris. Поскольку SUS3 рекомендует поддержку функций setenv и putenv, лучшим выходом будет все-таки использовать их, а для систем, которые не поддерживают setenv и putenv — включать в приложения собственные версии этих функций.