рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Программирование для операционной системы Linux

Программирование для операционной системы Linux - раздел Программирование,   Министерство Образования И Науки Рф Федеральное Аген...

 

Министерство образования и науки РФ

Федеральное агентство по образованию

Государственное образовательное учреждение высшего профессионального образования

«Ижевский государственный технический университет»

Факультет «Информатика и вычислительная техника»

Кафедра «Вычислительная техника»

 

 

Методические указания для выполнения лабораторных работ

«Программирование для операционной системы Linux»

по курсу «Операционные системы»

для студентов специальности 23.01.00

«Вычислительные машины, комплексы, системы и сети»

 

Ижевск 2010

 

Оглавление


ОКРУЖЕНИЕ.................................................................................................................................... 3

Введение в окружение.................................................................................................................. 3

Процессы в Linux.......................................................................................................................... 5

Массив environ............................................................................................................................. 10

Чтение окружения: getenv()........................................................................................................ 11

Запись окружения: setenv()......................................................................................................... 12

Сырая модификация окружения: putenv()................................................................................ 13

Удаление переменной окружения: unsetenv()........................................................................... 15

Очистка окружения: clearenv()................................................................................................... 16

ФАЙЛОВЫЙ ВВОД-ВЫВОД........................................................................................................ 18

Обзор механизмов ввода-вывода в Linux................................................................................. 18

Файловые дескрипторы.............................................................................................................. 18

Открытие файла: системный вызов open()............................................................................... 19

Закрытие файла: системный вызов close()................................................................................ 20

Чтение файла: системный вызов read()..................................................................................... 22

Запись в файл: системный вызов write()................................................................................... 25

Произвольный доступ: системный вызов lseek()..................................................................... 27

МНОГОЗАДАЧНОСТЬ................................................................................................................... 31

Основы многозадачности в Linux............................................................................................ 31

Использование getpid() и getppid().......................................................................................... 33

Порождение процесса................................................................................................................. 34

Замена образа процесса.............................................................................................................. 36

Функции семейства exec().......................................................................................................... 38

ФАЙЛОВАЯ СИСТЕМА................................................................................................................ 42

Типы файлов................................................................................................................................ 42

Индексные дескрипторы и жесткие ссылки............................................................................ 44

Режим файла................................................................................................................................ 47

УТИЛИТА MAKE............................................................................................................................ 51

Введение...................................................................................................................................... 51

Мультифайловое программирование....................................................................................... 51

Автоматическая сборка............................................................................................................. 53

БИБЛИОТЕКИ................................................................................................................................. 57

Введение в библиотеки............................................................................................................. 57

Пример статической библиотеки............................................................................................. 58

Пример совместно используемой библиотеки....................................................................... 60


БИБЛИОГРАФИЯ………...………………………………………………………………………..70

 

Методические указания

 

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

 

Требования к оформлению работ

По каждой лабораторной работе составляется отчет, который должен содержать:

-- Титульный лист;

-- название и цель работы;

-- лабораторное задание;

-- описание данных и при необходимости описание структуры программы;

-- текст программы;

-- результаты выполнения программы;

-- выводы по результатам выполнения программы.

 

ОКРУЖЕНИЕ

Введение в окружение

Окружение (environment) или среда - это набор пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, доступный каждому пользовательскому процессу. Иными словами, окружение - это набор переменных окружения. Если вы используете оболочку, отличную от bash, то не все примеры этой главы могут быть воспроизведены.

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

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ env > myenv

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Или так:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ env | more

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Или так:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ env | less

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

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

Значение каждой переменной окружения изначально представляет собой строковую константу (строку). Интерпретация значений переменных полностью возлагается на программу. Иными словами, все переменные окружения имеют тип char*, а само окружение имеет тип char**. Чтобы вывести на экран значение какой-нибудь переменной окружения, достаточно набрать echo $ИМЯ_ПЕРЕМЕННОЙ:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ echo $USER

df00

$ echo $HOME

/home/df00

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Вообще говоря, при работе с оболочкой bash, запись $ИМЯ_ПЕРЕМЕННОЙ заменяется на само значение переменной, если только эта запись не встречается в кавычках, апострофах или в комментариях. В нашем случае, например, запись $HOME заменяется на /home/df00. То есть команда mkdir $HOME/mynewdir создаст в нашем домашнем каталоге подкаталог mynewdir.

В разных системах и у разных пользователей окружение отличается не только значениями переменных, но и наличием/отсутствием этих переменных. Пользователи, использующие универсальные MUA (Mail User Agent), наподобие Mozilla-mail, Kmail или Sylpheed вряд ли будут иметь в своем окружении (по крайней мере с пользой) переменные MAIL или MAILDIR. А пользователям mutt, pine или elm (с довесками в виде fetchmail/getmail, procmail и проч.) эти переменные жизненно необходимы. Пользователь, не использующий графические оболочки, вряд ли будет иметь в своем окружении переменную QTDIR. Ниже приведены те переменные окружения, которые есть почти у всех пользователей Linux:

USER имя текущего пользователя
HOME путь к домашнему каталогу текущего пользователя
PATH список каталогов, разделенных двоеточиями, в которых производится "поиск" программ
PWD текущий каталог
OLDPWD предыдущий текущий каталог
TERM тип терминала
SHELL текущая командная оболочка
HOSTNAME имя машины
QTDIR расположение библиотеки QT
MAIL почтовый ящик
LD_LIBRARY_PATH место "поиска" дополнительных библиотек
MANPATH место поиска файлов man-страниц (каталоги, разделенные двоеточием)
LANG язык и кодировка пользователя (иногда LANGUAGE)
DISPLAY текущий дисплей в X11

 

Помимо переменных окружения, командные оболочки, такие как bash располагают собственным набором пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ. Это переменные оболочки. Набор таких переменных называют окружением (или средой) оболочки. Эти переменные чем-то напоминают локальные (стековые) переменные в языке C. Они недоступны для других программ (в том числе и для env) и используются в основном в сценариях оболочки. Чтобы задать переменную оболочки, достаточно написать в командной строке ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ MYVAR=Hello

$ echo $MYVAR

Hello

$ env | grep MYVAR

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Однако, при желании, можно включить локальную переменную оболочки в основное окружение. Для этого используется команда export:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ export MYVAR

$ env | grep MYVAR

MYVAR=Hello

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Можно сделать сразу так:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ export MYNEWVAR=Goodbye

$ echo $MYNEWVAR

Goodbye

$ env | grep MYNEWVAR

MYNEWVAR=Goodbye

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

Теперь разберемся с тем, откуда берется окружение. Любая запущенная и работающая в Linux программа - это процесс. Запуская дважды одну и ту же программу, вы получаете два процесса. У каждого процесса (кроме init) есть свой процесс-родитель. Когда вы набираете в командной строке vim, в системе появляется новый процесс, соответствующий текстовому редактору vim; родительским процессом здесь будет оболочка (bash, например). Для самой оболочки новый процесс будет дочерним. Сейчас же важно одно: новый процесс получает копию родительского окружения. Из этого правила существует несколько исключений, но мы пока об этом говорить не будем. Важно то, что у каждого процесса своя независимая копия окружения, с которой процесс может делать все что угодно. Если процесс завершается, то копия теряется; если процесс породил другой, дочерний процесс, то этот новый процесс получает копию окружения своего родителя. Мы еще неоднократно столкнемся с окружением при изучении многозадачности.

 

 

Процессы в Linux

Сухая формулировка говорит нам, что процесс - это совокупность программного кода и данных, загруженных в память ЭВМ. На первый взгляд процесс - это… Код процесса не обязательно должен выполняться в текущий момент времени, так… 1. Работающий процесс – в данный момент код процесса выполняется.

Массив environ

В заголовочном файле unistd.h объявлен внешний двумерный массив environ: … extern char ** environ;

Лабораторные задания

 

В соответствии с вариантом задания разработать и отладить программу. Исходные данные вводятся с клавиатуры и записываются в переменную окружения. Программа читает эти данные, после обработки результаты помещаются в переменную «OUTPUT». Все задания компилировать с помощью утилиты MAKE.

Варианты заданий

1. Из текста удалить четвертое слово.

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

3. В тексте добавить после третьего слова новое слово.

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

5. В тексте удалить лишние пробелы.

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

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

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

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

10. Из переменной, содержащей сведения о студентах сформировать переменную, в которую входят только фамилии.

11. Из текста выбрать четные слова.

12. В тексте поменять местами первое и последнее слова.

13. Из текста удалить все нечетные слова.

14. Выбрать из текста слова стоящие на позициях, которые соответствуют ряду простых чисел.

15. Из текста удалить каждое третье слово.

16. В тексте заменить все пробелы на символ «&».

17. Создать переменную записать в нее два слова, первое слово состоит из первых букв слов исходного текста, второе – из последних.

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

19. Все гласные буквы в исходном тексте, заменить на восклицательный знак.

20. Удалить каждую вторую букву каждого второго слова исходного текста.

ФАЙЛОВЫЙ ВВОД-ВЫВОД

Обзор механизмов ввода-вывода в Linux

С точки зрения модели КИС (Клиент-Интерфейс-Сервер), сервером стандартных механизмов ввода вывода языка C (printf, scanf, FILE*, fprintf, fputc и т.… Пользовательские программы взаимодействуют с ядром операционной системы…  

Файловые дескрипторы

Работа с локальными файловыми системами, межсетевое взаимодействие, работа с аппаратными устройствами, - все это осуществляется в Linux посредством… Вы уже знаете из предыдущей главы, что при запуске программы в системе… Файловый дескриптор (file descriptor) - это целое число (int), соответствующее открытому файлу. Дескриптор,…

Лабораторные задания.

В соответствии с вариантом задания разработать и отладить программу. Исходные данные хранятся в текстовом файле. Программа читает эти данные, после обработки результаты помещаются в файл «OUTPUT.TXT». Все задания компилировать с помощью утилиты MAKE.

Варианты заданий смотреть в главе «Переменные окружения»

 

МНОГОЗАДАЧНОСТЬ

Итак, многозадачности не существует. Действительно, любой компьютер - это императивная машина, т.е. машина, основанная на последовательном анализе… Чем же программа отличается от процесса? Программа - это нечто, готовое к…  

Основы многозадачности в Linux

… $ ps -e …

Порождение процесса

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

Замена образа процесса

… int execve (const char * path, char const * argv[], char * const envp[]); …

Лабораторные задания

Разработать программу, выполняющую "разветвление" посредством системного вызова fork(). Вывести на экран идентификаторы PID и PPID для родительского и дочернего процессов. Использовать функцию перенаправления стандартного вывода в файл. Все задания компилировать с помощью утилиты MAKE.

 

Варианты заданий

 

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

2. Приостановить на 1 с родительский процесс. Выполнить в дочернем процессе один из системных вызовов exec(), передав ему в качестве параметра стандартную программу ps. Аналогично выполнить вызов ps в родительском процессе. Результаты работы команд ps в обоих процессах перенаправить в один и тот же файл.

3. Определить в программе глобальную переменную var со значением, равным 1. Переопределить стандартный вывод и родительского, и дочернего процессов в один и тот же файл. До выполнения разветвления увеличить на 1 переменную var, причем вывести ее значение, как до увеличения, так и после. В родительском процессе увеличить значение переменной на 3, а в дочернем на 5. Вывести значение переменной до увеличения и после него внутри каждого из процессов. Результат пояснить.

4. Приостановить на 1 с дочерний процесс. В дочернем процессе с помощью системного вызова system() выполнить стандартную команду ps, перенаправив вывод в файл номер 1. Вслед за этим завершить дочерний процесс. В родительском процессе вызвать ps и перенаправить в файл номер 2. Освободить ячейку таблицы процессов порожденного процесса.

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

6. Программа порождает через каждые 2 секунды 5 новых процессов. Каждый из этих процессов выполняется заданное время и останавливается, сообщая об этом родителю. Программа-родитель выводит на экран все сообщения об изменениях в процессах.

7. Программа запускает с помощью функции exec() новый процесс. Завершить процесс-потомок раньше формирования родителем вызова. Повторить запуск программы при условии, что процесс потомок завершается после формирования вызова wait(). Проанализировать результаты.

8. Процесс открывает N файлов, реально существующих на диске либо вновь созданных. Разработать программу, демонстрирующую динамику формирования таблицы описателей файлов и изменения информации в ее элементах (при изменении информации в файлах). Например, сценарий программы может быть следующим:

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

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

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

    • неявное открытие стандартного файла ввода;
    • неявное открытие стандартного файла вывода;
    • неявное открытие стандартного файла вывода ошибок;
    • открытие пользовательского файла;
    • закрытие стандартного файла ввода (моделирование close(0));
    • получение копии дескриптора пользовательского файла (моделирование dup(fd), где fd - дескриптор пользовательского файла);
    • закрытие пользовательского файла (моделирование close(fd), где fd - дескриптор пользовательского файла).

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

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

11. Путь N процессов осуществляют доступ к одному и тому же файлу на диске (но с разными режимами доступа). Разработать программу, демонстрирующую динамику формирования таблицы файлов и изменения ее элементов (при перемещении указателей чтения-записи, например). Например, сценарий программы может быть следующим:

    1. открытие файла процессом 0 для чтения;
    2. открытие файла процессом 1 для записи;
    3. открытие файла процессом 2 для добавления;
    4. чтение указанного числа байт файла процессом 0;
    5. запись указанного числа байт в файл процессом 1;
    6. добавление указанного числа байт в файл процессом 2.

После каждого из этапов печатаются таблицы файлов всех процессов.

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

    1. неявное открытие стандартного файла ввода;
    2. неявное открытие стандартного файла вывода;
    3. неявное открытие стандартного файла вывода ошибок;
    4. открытие первого пользовательского файла;
    5. открытие второго пользовательского файла;
    6. запись 20 байт в первый файл;
    7. чтение 15 байт из второго файла;
    8. запись 45 байт в первый файл.

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

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

    1. неявное открытие стандартного файла ввода;
    2. неявное открытие стандартного файла вывода;
    3. неявное открытие стандартного файла вывода ошибок;
    4. открытие первого пользовательского файла;
    5. открытие второго пользовательского файла;
    6. открытие третьего пользовательского файла.

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

14. Пусть каждый из N процессов осуществляет доступ к Pi файлам (i=1..N). Далее пусть M<N процессов породили процессы-потомки (с помощью системного вызова fork()) и среди этих потомков K<M процессов дополнительно открыли еще Sj файлов (j=1..K). Разработать программу, демонстрирующую динамику формирования таблиц открытых файлов процессов. Например, сценарий программы может быть следующим:

    1. процесс 0 открывает два файла (общее число открытых файлов, включая стандартные файлы, равно пяти);
    2. процесс 1 открывает два файла (общее число открытых файлов, включая стандартные файлы, равно пяти);
    3. процесс 2 открывает два файла (общее число открытых файлов, включая стандартные файлы, равно пяти);
    4. процесс 0 порождает процесс 3, который наследует таблицу открытых файлов процесса 0;
    5. процесс 1 порождает процесс 4, который наследует таблицу открытых файлов процесса 1;
    6. процесс 4 дополнительно открыл ещё два файла.

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

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

    1. неявное открытие стандартного файла ввода;
    2. неявное открытие стандартного файла вывода;
    3. неявное открытие стандартного файла вывода ошибок;
    4. чтение из стандартного файла ввода 5 байт;
    5. открытие пользовательского файла;
    6. закрытие стандартного файла ввода (моделирование close(0));
    7. получение копии дескриптора пользовательского файла (моделирование dup(fd), где fd - дескриптор пользовательского файла);
    8. закрытие пользовательского файла (моделирование close(fd), где fd - дескриптор пользовательского файла);
    9. чтение из "стандартного" файла ввода 10 байт.

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

16. Пусть процесс, открывший N файлов, перед порождением процесса-потомка с помощью системного вызова fork() закрывает K<N файлов. Процесс-потомок сразу после порождения закрывает M<N-K файлов и через некоторое время завершается (в это время процесс-предок ожидает его завершения). Разработайте программу, демонстрирующую динамику изменения данных в системе управления вводом-выводом ОС UNIX (таблицы файлов и таблицы открытых файлов процессов). Например, сценарий программы может быть следующим:

    1. открытие процессом-предком стандартных файлов ввода-вывода и четырёх пользовательских файлов для чтения;
    2. закрытие процессом-предком двух пользовательских файлов;
    3. процесс-предок порождает процесс, который наследует таблицы файлов и открытых файлов процесса-предка;
    4. завершается процесс-потомок.

После каждого из этапов печатаются таблицы файлов и открытых файлов для обоих процессов.

17. Пусть процесс осуществляет действия в соответствии со следующим фрагментом программы:

16. main()17. {18. ...19. fd=creat(temporary, mode); /* открыть временный файл */20. ...21. /* выполнение операций записи-чтения */22. ...23. close(fd);24. }

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

18. Процесс 1 открывает файл и порождает потомка 2. Процесс 2 по сигналу SIG1 от процесса 1 начинает писать в файл, по сигналу SIG2 прекращает запись, а потом по сигналу SIG1 завершается. Сигнал SIG1 поступает с задержкой в 1 секунду относительно первого сигнала SIG2.

19. Процесс 1 открывает файл и порождает потомка 2. Процесс 1 читает данные из файла, процесс 2 пишет данные в файл следующим образом: по сигналу SIG1 от процесса 1 процесс 2 записывает в файл N чисел и посылает процессу 1 сигнал окончания записи; процесс 1 по этому сигналу считывает данные и посылает процессу 2 сигнал SIG1. Процесс 2 всегда пишет данные в начало файла. Организовать M циклов записи/чтения. Прочитанные данные выводятся на экран.

20. Процесс 1 открывает существующий файл и порождает потомка 2. Процесс 1 считывает N байт из файла, выводит их на экран и посылает сигнал SIG1 процессу 2. Процесс 2 также считывает N байт из файла, выводит их на экран и посылает сигнал SIG1 процессу 1. Если одному из процессов встретился конец файла, то он посылает другому процессу сигнал SIG2 и они оба завершаются.

ФАЙЛОВАЯ СИСТЕМА

Типы файлов

Начнем с типов файлов. С точки зрения содержимого или назначения, файлов огромное множество (изображения, музыка, тексты, исполняемые файлы программ… Первый тип - обычные файлы (regular files). Эти файлы предназначены для… Обычные файлы, как мы уже знаем, создаются при помощи системных вызовов open() и creat(). С точки зрения пользователя,…

Индексные дескрипторы и жесткие ссылки

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

Индексные дескрипторы (иноды, i-nodes, индексы) - это структура данных, содержащая все метаданные файла, т.е. права доступа, даты создания, последней модификации, размер файла и т.д., а также номер, который уникален в рамках одного диска, раздела или иного носителя информации. Индексные дескрипторы не содержат в себе имя файла. В ОС Unix файлы связываются с упомянутым номером, а не с его именем. Имена файлов содержат каталоги, таким образом содержимое каталогов можно условно представить в виде списка имен файлов и номеров индексных дескрипторов. Пара, состоящая из имени файла и номера индексного дескриптора называется жесткой ссылкой, далее будем говорить просто ссылка. Иными словами, у каждого файла есть свой уникальный номер, через который осуществляется взаимодействие с данными. Чтобы посмотреть этот номер, достаточно вызвать ls с опцией -i (--inode - длинный вариант).

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ touch myfile1

$ touch myfile2

$ ls -i

6373383 myfile1 6373384 myfile2

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ls -li /dev/null

1260 crw-rw-rw- 1 rootroot 1, 3 2010-02-09 17:08 /dev/null

$ mkfifo myfifo

$ ls -li myf

6373385 prw-r--r-- 1 df00 df00 0 2010-02-09 21:57 myf

$ mkdir mydir

$ ls -lid mydir

5898479 drwxr-xr-x 2 df00 df00 4096 2010-02-09 22:20 mydir

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Как видим, у каждого файла есть свой номер (индексный дескриптор). Каталоги–не исключение. Но обратите внимание на число, которое идет после поля прав доступа. В нашем примере у /dev/null и у myfifo оно равно единице, а у каталога mydir - 2. Это число показывает количество ссылок на данный индексный дескриптор в файловой системе. И тут мы подходим к последней сущности, связанной с файлами.

То, что мы привыкли называть файлами - это всего лишь ссылки. Естественно, нам приятнее работать с именем /dev/null, а не с дескриптором номер 252. Но самое интересное в том, что на один и тот же индексный дескриптор в файловой системе может быть сколь угодно много ссылок (в пределах разумного, естественно). Третье поле вывода ls -l как раз и показывает это количество.

При создании обычного файла, устройства, FIFO, символической ссылки или локального сокета в файловой системе появляется индексный дескриптор и одна ссылка на него. Но при создании каталога создаются сразу две ссылки. Рассмотрим пример, объясняющий такое поведение.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ls -lid mydir

5898479 drwxr-xr-x 2 df00 df00 4096 2010-02-09 22:20 mydir

$ ls -lia mydir

5898479 drwxr-xr-x 2 df00 df00 4096 2010-02-09 22:20 .

5898448 drwxr-xr-x 3 df00 df00 4096 2010-02-09 22:20 ..

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Как видим, в каталоге mydir находится ссылка на тот же номер (точка), а так же ссылка на родительский каталог (две точки). Этим и объясняется наличие двух ссылок на создаваемый каталог.

Итак, мы выяснили, что файловая система в обычном понимании - это набор ссылок, причем одному дескриптору может соответствовать несколько ссылок. Теперь важно понять две вещи.

Все ссылки на один индексный дескриптор равноправны: нет ни главных, ни второстепенных.

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

Таким образом, чтобы удалить файл, нужно удалить все ссылки. Этим и объясняется название системного вызова unlink(). После удаления последней ссылки, файловая система автоматически вычёркивает файл из своих закромов.

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

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ cd mydir

$ ls

$ touch file1

$ ln -s file1 mylink1

$ ln file1 mylink2

$ echo "i am here" > file1

$ ls -li

491528 -rw-r--r-- 2 df00 df00 10 2010-02-09 22:35 file1

491617 lrwxrwxrwx 1 nn nn 5 2010-02-09 22:36 mylink1 -> file1

491528 -rw-r--r-- 2 nn nn 10 2010-02-09 22:36 mylink2

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

mylink1 – это символическая ссылка; то есть особый тип файла, хранящий путь к другому файлу. Обратите внимание, что mylink1 соответствует отдельный индексный дескриптор с номером 491617. А вот file1 и mylink2 - это абсолютно равноправные ссылки на один и тот же индексный дескриптор с номером 491528. Таким образом, символическая ссылка указывает на имя, а жесткая ссылка - на индексный дескриптор. Если удалить ссылку file1, то символическая ссылка mylink1 "осиротеет". Однако это не является ошибкой файловой системы.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ rm file1

$ ca tmylink1

cat: mylink1: No such file or directory

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Программа rm вызвала системный вызов unlink() и удалила одну из двух ссылок на индексный дескриптор с номером 491528. Однако другая ссылка (mylink2) продолжает жить и здравствовать.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ls -li

491617 lrwxrwxrwx 1 nn nn 5 2010-02-09 22:35 mylink1 -> file1

491528 -rw-r--r-- 1 nn nn 10 2010-02-09 22:36 mylink2

$ cat mylink2

i am here

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

В выводе ls мы видим, что на индексный дескриптор 491528 осталась одна ссылка. Удалив её, мы уничтожим файл окончательно и освободим номер индексного дескриптора.

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

 

Режим файла

… Биты режима файла можно разделить на 3 группы: биты 0-8: основные права доступа;

Лабораторные задания

Все задания компилировать с помощью утилиты MAKE.

1. Определить количество файлов с указанным расширением, находящихся в заданном каталоге. Если таких файлов нет, то выдать на экран сообщение. Имя каталога и расширение передаются в программу через параметры командной строки.

2. Прочитать содержимое указанного каталога в файл. Если каталог пуст, выдать на экран сообщение. Имя каталога вводится с клавиатуры.

3. Просмотреть содержимое текущего каталога, ввести с клавиатуры имя одного из файлов. Если этот файл имеет ненулевую длину, то вывести его содержимое на экран.

4. Если указанный в параметре командной строки файл не имеет установленного атрибута разрешения для выполнения, то необходимо установить этот параметр.

5. Проверить является ли указанный в параметре файл каталогом. Вывести соответствующую информацию на экран. Если это каталог, то установить разрешение записи в этот каталог.

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

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

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

9. Прочитать содержимое указанного каталога в файл. Если каталог не пуст, выдать на экран сообщение. Имя каталога передается через параметр командной строки.

10. Распечатать из текущего каталога содержащие цифры имена всех файлов с расширениями *.c и *.cpp.

11. Создать в каталоге "./links" символические ссылки на все файлы текущего каталога с добавлением к имени файла ".link".

12. Копировать в каталог, имя которого вводится с клавиатуры, файлы, у которых имя начинается с букв "a" или "z", если эти файлы не являются каталогами.

13. Разработать программу, которая осуществляет просмотр текущего каталога и выводит на экран его содержимое группами в порядке возрастания числа ссылок на файлы (в том числе имена каталогов). Группа представляет собой объединение файлов с одинаковым числом ссылок на них.

14. Разработать программу, которая просматривает текущий каталог и выводит на экран имена всех встретившихся в нем файлов с заданным расширением. Затем осуществляется переход в родительский каталог, который затем становится текущим, и указанные выше действия повторяются до тех пор, пока текущим каталогом не станет корневой каталог. 15. Разработать программу, которая просматривает текущий каталог и выводит на экран имена всех встретившихся в нем обычных файлов. Затем осуществляется переход в родительский каталог, который затем становится текущим, и указанные выше действия повторяются до тех пор, пока текущим каталогом не станет корневой каталог.

16. Разработать программу, которая выводит на экран имена тех каталогов, которые находятся в текущем каталоге и не содержат в себе подкаталогов.

17. Разработать программу, которая выводит на экран имена тех каталогов, которые находятся в текущем каталоге и содержат в себе подкаталоги.

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

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

20. Разработать программу, которая выводит на экран содержимое текущего каталога в алфавитном порядке. Каталоги не выводить.

 

УТИЛИТА MAKE

Введение

Утилита make, входящая в состав практически всех Unix-подобных операционных систем - это традиционное средство, применяемое для сборки программных проектов. Она является универсальной программой для решения широкого круга задач, где одни файлы должны автоматически обновляться при изменении других файлов.

При запуске программа make читает файл с описанием проекта (make-файл) и, интерпретируя его содержимое, предпринимает необходимые действия. Файл с описанием проекта представляет собой текстовой файл, где описаны отношения между файлами проекта, и действия, которые необходимо выполнить для его сборки.

Типичный make-файл проекта содержит несколько правил. Каждое из правил имеет некоторую цель и некоторые зависимости. Смыслом работы make является достижение цели, которую она выбрала в качестве главной цели (default goal). Если главная цель является именем действия (то есть абстрактной целью), то смысл работы make заключается в выполнении соответствующего действия. Если же главная цель является именем файла, то программа make должна построить самую "свежую" версию указанного файла.

Основным "строительным элементом" make-файла являются правила (rules). В общем виде правило выглядит так:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

<цель_1><цель_2> ... <цель_n>: <зависимость_1><зависимость_2> ... <зависимость_n>

<команда_1>

<команда_2>

...

<команда_n>

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

Мультифайловое программирование

Куда лучше разбросать исходный код по нескольким файлам (осмысленно, по какому-нибудь критерию), и компилировать каждый такой файл отдельно. Как вы… Давайте сначала разберемся, как из исходного файла получается бинарник.… Вернемся к объектному коду. Эти самые "вкрапления" (самое главное среди них - таблица символов) позволяют…

Автоматическая сборка

Выход из сложившейся ситуации есть. Это утилита make, которая работает со своими собственными сценариями. Сценарий записывается в файле с именем… То, что выполняет утилита make, называется сборкой проекта, а сама утилита… Любой Makefile состоит из трех элементов: комментарии, макроопределения и целевые связки (или просто связки). В свою…

БИБЛИОТЕКИ

Введение в библиотеки

Как уже неоднократно упоминалось в предыдущей главе, библиотека - это набор скомпонованных особым образом объектных файлов. Библиотеки подключаются к основной программе во время линковки. По способу компоновки библиотеки подразделяют на архивы (статические библиотеки, static libraries) и совместно используемые (динамические библиотеки, shared libraries). В Linux, кроме того, есть механизмы динамической подгрузки библиотек. Суть динамической подгрузки состоит в том, что запущенная программа может по собственному усмотрению подключить к себе какую-либо библиотеку. Благодаря этой возможности создаются программы с подключаемыми плагинами, такие как XMMS. В этой главе мы не будем рассматривать динамическую подгрузку, а остановимся на классическом использовании статических и динамических библиотек.

С точки зрения модели КИС, библиотека - это сервер. Библиотеки несут в себе одну важную мысль: возможность использовать одни и те же механизмы в разных программах. В Linux библиотеки используются повсеместно, поскольку это очень удобный способ "не изобретать велосипеды". Даже ядро Linux в каком-то смысле представляет собой библиотеку механизмов, называемых системными вызовами.

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

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

Рассмотрим преимущества и недостатки статических и совместно используемых библиотек. Статические библиотеки делают программу более автономной: программа, скомпонованная со статической библиотекой может запускаться на любом компьютере, не требуя наличия этой библиотеки (она уже "внутри" бинарника). Программа, скомпонованная с динамической библиотекой, требует наличия этой библиотеки на том компьютере, где она запускается, поскольку в бинарнике не код, а ссылка на код библиотеки. Не смотря на такую зависимость, динамические библиотеки обладают двумя существенными преимуществами. Во-первых, бинарник, скомпонованный с совместно используемой библиотекой меньше размером, чем такой же бинарник, с подключенной к нему статической библиотекой (статически скомпонованный бинарник). Во-вторых, любая модернизация динамической библиотеки, отражается на всех программах, использующих ее. Таким образом, если некоторую библиотеку foo используют 10 программ, то исправление какой-нибудь ошибки в foo или любое другое улучшение библиотеки автоматически улучшает все программы, которые используют эту библиотеку. Именно поэтому динамические библиотеки называют совместно используемыми. Чтобы применить изменения, внесенные в статическую библиотеку, нужно пересобрать все 10 программ.

В Linux статические библиотеки обычно имеют расширение .a (Archive), а совместно используемые библиотеки имеют расширение .so (SharedObject). Хранятся библиотеки, как правило, в каталогах /lib и /usr/lib.

 

 

Пример статической библиотеки

Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями: h_world() и g_world(), которые выводят на экран "HelloWorld" и "GoodbyeWorld" соответственно. Начнем со статической библиотеки.

 

 

Начнем с интерфейса. Создадим файл world.h:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* world.h */

void h_world (void);

void g_world (void);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Здесь просто объявлены функции, которые будут использоваться. Теперь надо реализовать серверы. Создадим файл h_world.c:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* h_world.c */

#include<stdio.h>

#include "world.h"

 

void h_world (void)

{

printf ("Hello Worldn");

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Теперь создадим файл g_world.c, содержащий реализацию функции g_world():

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* g_world.c */

#include <stdio.h>

#include "world.h"

 

void g_world (void)

{

printf ("Goodbye Worldn");

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

Теперь создадим файл main.c. Это клиент, который будет пользоваться услугами сервера:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* main.c */

#include "world.h"

 

int main (void)

{

h_world ();

g_world ();

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Теперь напишем сценарий для make. Для этого создаем Makefile:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

# Makefile for World project

 

binary: main.o libworld.a

gcc -o binary main.o -L. -lworld

 

main.o: main.c

gcc -c main.c

 

libworld.a: h_world.o g_world.o

ar cr libworld.a h_world.o g_world.o

 

h_world.o: h_world.c

gcc -c h_world.c

 

g_world.o: g_world.c

gcc -c g_world.c

 

clean:

rm -f *.o *.a binary

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Не забывайте ставить табуляции перед каждым правилом в целевых связках. Собираем программу:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ make

gcc -c main.c

gcc -c h_world.c

gcc -c g_world.c

ar cr libworld.a h_world.o g_world.o

gcc -o binary main.o -L. -lworld

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Осталось только проверить, работает ли программа и разобраться, что же мы такое сделали:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ./binary

HelloWorld

GoodbyeWorld

$

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Итак, в приведенном примере появились три новые вещи: опции -l и -L компилятора, а также команда ar. Начнем с последней. Как вы уже догадались, команда ar создает статическую библиотеку (архив). В нашем случае два объектных файла объединяются в один файл libworld.a. В Linux практически все библиотеки имеют префикс lib.

Как уже говорилось, компилятор gcc сам вызывает линковщик, когда это нужно. Опция -l, переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарнику библиотеку. Как вы уже заметили, у имени библиотеки "обрублены" префикс и суффикс. Это делается для того, чтобы создать "видимое безразличие" между статическими и динамическими библиотеками. Но об этом речь пойдет в других главах книги. Сейчас важно знать лишь то, что и библиотека libfoo.so и библиотека libfoo.a подключаются к проекту опцией -lfoo. В нашем случае libworld.a "урезалось" до -lworld.

Опция -L указывает линковщику, где ему искать библиотеку. В случае, если библиотека располагается в каталоге /lib или /usr/lib, то вопрос отпадает сам собой и опция -L не требуется. В нашем случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает текущий каталог) необходима.

 

Пример совместно используемой библиотеки

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

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

# MakefileforWorldproject

 

binary: main.o libworld.so

gcc -o binary main.o -L. -lworld -Wl,-rpath,.

 

main.o: main.c

gcc -c main.c

 

libworld.so: h_world.o g_world.o

gcc -shared -o libworld.so h_world.o g_world.o

 

h_world.o: h_world.c

gcc -c -fPIC h_world.c

 

g_world.o: g_world.c

gcc -c -fPIC g_world.c

 

clean:

rm -f *.o *.so binary

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Внешне ничего не изменилось: программа компилируется, запускается и выполняет те же самые действия, что и в предыдущем случае. Изменилась внутренняя суть, которая играет для программиста первоочередную роль. Рассмотрим все по порядку.

Правило для сборки binary теперь содержит пугающую опцию “-Wl,-rpath,.”. Ничего страшного тут нет. Как уже неоднократно говорилось, компилятор gcc сам вызывает линковщик ld, когда это надо и передает ему нужные параметры сборки, избавляя нас от ненужной платформенно-зависимой волокиты. Но иногда мы все-таки должны вмешаться в этот процесс и передать линковщику "свою" опцию. Для этого используется опция компилятора -Wl,option,optargs,... Расшифровываю: передать линковщику (-Wl) опцию option с аргументами optargs. В нашем случае мы передаем линковщику опцию -rpath с аргументом . (точка, текущий каталог). Возникает вопрос: что означает опция -rpath? Как уже говорилось, линковщик ищет библиотеки в определенных местах; обычно это каталоги /lib и /usr/lib, иногда /usr/local/lib. Опция -rpath просто добавляет к этому списку еще один каталог. В нашем случае это текущий каталог. Без указания опции -rpath, линковщик "молча" соберет программу, но при запуске нас будет ждать сюрприз: программа не запустится из-за отсутствия библиотеки. Попробуйте убрать опцию -Wl,-rpath,. из Makefile и пересоберите проект. При попытке запуска программа binary завершится с кодом возврата 127 (о кодах возврата будет рассказано в последующих главах). То же самое произойдет, если вызвать программу из другого каталога. Верните обратно -Wl,-rpath,., пересоберите проект, поднимитесь на уровень выше командой cd .. и попробуйте запустить бинарник командой world/binary. Ничего не получится, поскольку в новом текущем каталоге библиотеки нет.

Есть один способ не передавать линковщику дополнительных опций при помощи -Wl - это использование переменной окружения LD_LIBRARY_PATH. В последующих главах мы будем подробно касаться темы окружения (environment). Сейчас лишь скажу, что у каждого пользователя есть так называемое окружение (environment) представляющее собой набор пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, используемых программами. Чтобы посмотреть окружение, достаточно набрать команду env. Чтобы добавить в окружение переменную, достаточно набрать export ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, а чтобы удалить переменную из окружения, надо набрать export -n ПЕРЕМЕННАЯ. Будьте внимательны: export - это внутренняя команда оболочки BASH; в других оболочках (csh, ksh, ...) используются другие команды для работы с окружением. Переменная окружения LD_LIBRARY_PATH содержит список дополнительных "мест", разделенных двоеточиями, где линковщик должен искать библиотеку.

Не смотря на наличие двух механизмов передачи информации о нестандартном расположении библиотек, лучше помещать библиотеки в конечных проектах в /lib и в /usr/lib. Допускается расположение библиотек в подкаталоги /usr/lib и в /usr/local/lib (с указанием -Wl,-rpath). Но заставлять конечного пользователя устанавливать LD_LIBRARY_PATH почти всегда является плохим стилем программирования.

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

Последнее отличие - опции -fPIC (-fpic) при компиляции h_world.c и g_world.c. Эта опция сообщает компилятору, что объектные файлы, полученные в результате компиляции должны содержать позиционно-независимый код (PIC — Position Independent Code), который используется в динамических библиотеках. В таком коде используются не фиксированные позиции (адреса), а плавающие, благодаря чему код из библиотеки имеет возможность подключаться к программе в момент запуска.

 

Лабораторные задания

В соответствии с вариантом задания разработать и отладить библиотеку. Все задания компилировать с помощью утилиты MAKE.

1. В тексте определить количество символов, которые не являются ни цифрами, ни буквами.

2. Для заданной матрицы получить вектор, каждый элемент которой равен сумме элементов строки матрицы.

3. Выделить первое и последнее слова текста.

4. Дана матрица A(5,5) и вектор X(5). Вычислить произведение матрицы на вектор.

5. Дана матрица B(4,5). Найти столбец с максимальной суммой элементов.

6. Даны два массива по 10 элементов каждый. Найти сумму квадратов разностей

элементов массивов с одинаковыми индексами.

7. В тексте вставить между вторым и третьим словом новое слово.

8. Для матрицы определить каких элементов больше: положительных или отрицательных.

9. В тексте определить количество заключенных в круглые скобки символов.

10. Вывести на экран второе и четвертое слова произвольной строки.

11. В тексте найти и вывести слова, содержащие сочетание символов LF.

12. Для квадратной матрицы найти сумму элементов, находящихся выше главной диагонали.

13. Поменять элементы массива первый с последним, второй с предпоследним и т.д.

14. В матрице, в строке содержащей нуль, расположить элементы по убыванию.

15. В матрице максимальный элемент строки заменить средним арифметическим этой строки.

16. В матрице определить максимальный элемент каждого столбца и записать их в массив.

17. Создать матрицу. Найти две строки в которых элементы одинаковы, но стоят в разной последовательности.

18. В матрице определить сумму каждой строки и строчку с максимальной суммой записать в массив.

19. В матрице упорядочить элементы главной диагонали по возрастанию и найти сумму элементов стоящих под главной диагональю.

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

 

Библиография

1. Дансмур М. Операционная система UNIX и программирование на языке Си. /

Дансмур М., Дейвис Г. - М.: Радио и связь, 1989. – 192 с.

2. Рейчард К. Linux: справочник / К. Рейчард, П. Фолькердинг. - СПб.: Питер

Кон, 1999. – 480 с.

3. Робачевский А.М. Операционная система UNIX. - СПб.: BHV-Санкт-

Петербург, 1997. - 528 с.

4. Стивенс У. UNIX: взаимодействие процессов. – СПб.: Питер, 2003. – 576 с.

5. Теренс Чан Системное программирование на С++ для UNIX. К.: Издательская

группа BHV, 1997. - 592 с.

6. Хэвиленд К., Грэй Д., Салама Б. Системное программирование в UNIX. Руко-

водство программиста. – М., ДМК Пресс, 2000. – 368 с.

7. Серия статей Андрея Боровского, http://www.citforum.ru/programming/unix/borovsky/

8. Процессы в Linux, http://www.prolinux.ru/introduction/about-linux-processes/

9. Иванов Н. Н. «Программирование в Linux с нуля». http://www.lindevel.ru/zlp/

 


– Конец работы –

Используемые теги: Программирование, операционной, системы, Linux0.077

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

Что будем делать с полученным материалом:

Если этот материал оказался полезным для Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Еще рефераты, курсовые, дипломные работы на эту тему:

Лекция 1. Тема: Операционная система. Определение. Уровни операционной системы. Функции операционных систем. 1. Понятие операционной системы
Понятие операционной системы... Причиной появления операционных систем была необходимость создания удобных в... Операционная система ОС это программное обеспечение которое реализует связь между прикладными программами и...

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

Системы программирования и операционные системы
Обработчик должен иметь механизм выгрузки из оперативной памяти встроенный в него самого. Также программа должна иметь защиту от повторной установки в оперативную… Такие программы носят названия программ, резидентных в памяти Terminate and Stay Resident, TSR, или просто резидентных…

Системы программирования и операционные системы
Обработчик должен иметь механизм выгрузки из оперативной памяти встроенный в него самого. Также программа должна иметь защиту от повторной установки в оперативную… Такие программы носят названия программ, резидентных в памяти Terminate and Stay Resident, TSR, или просто резидентных…

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

Введение в операционные системы. Определение, назначение, состав и функции операционных систем
Государственное образовательное учреждение высшего профессионального образования... ТОЛЬЯТТИНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СЕРВИСА...

Микропроцессорные системы: система ДЦ-МПК, система "Юг"
Использован практический опыт внедрения линейных пунктов управления (ЛПУ) на 60 станциях в увязке с ЭЦ-4, ЭЦ-9, МРЦ-12, МРЦ-13. Выполнен переход на… В состав аппаратуры центрального пункта управления (ПУ) входят IBM-совместные… Круглосуточный режим работы аппаратных средств ПУ обеспечивается источниками бесперебойного питания, а также системой…

Операционная система LINUX
Первоначально она была создана как многозадачная система для миникомпьютеров и мэйнфреймов в середине 70-ых годов, но с тех пор она выросла в одну… LINUX многозадачная и многопользовательская операционная система для… Что делает LINUX столь отличным от других операционных систем - Он был создан и продолжает совершенствоваться и…

Разработка отказоустойчивой операционной системы реального времени для вычислительных систем с максимальным рангом отказоустойчивости
Таким образом, объектом исследования в рамках сетевой отказоустойчивой технологии становится ОСРВ - управляющее программное обеспечение особого… Данная дипломная работа посвящена разработке специализированной распределенной… Для полного освещения выбранной темы были поставлены следующие задачи 1. Провести анализ существующих операционных…

0.04
Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • По категориям
  • По работам