Рефераты. Администрирование локальных сетей p> ВВОД В Ы В О Д

FILE * stdin stdout stderr соответствует fd 0 1 2 связан с клавиатурой дисплеем

#include main(ac, av) char **av; { execl("/bin/sleep", "Take it easy", "1000", NULL);

}
Эти каналы достаются процессу "в наследство" от запускающего процесса и связаны с дисплеем и клавиатурой, если только не были перенаправлены. Кроме того, программа может сама явно открывать файлы (при помощи open, creat, pipe, fopen). Всего программа может одновременно открыть до определенное количество файлов в зависииости от настройки ядра. d) Процесс имеет уникальный номер, который он может узнать вызовом int pid = getpid(); а также узнать номер "родителя" вызовом int ppid = getppid();
Процессы могут по этому номеру посылать друг другу сигналы: kill(pid /* кому */, sig /* номер сигнала */); и реагировать на них signal (sig /*по сигналу*/, f /*вызывать f(sig)*/); e) Существуют и другие средства коммуникации процессов: семафоры, сообщения, общая память, сетевые коммуникации. f) Существуют некоторые другие параметры (контекст) процесса: например, его текущий каталог, который достается в наследство от процесса-"родителя", и может быть затем изменен системным вызовом chdir(char *имя_нового_каталога);
У каждого процесса есть свой собственный текущий рабочий каталог. К
"прочим" характеристикам отнесем также: управляющий терминал; группу процессов (pgrp); идентификатор (номер) владельца процесса (uid), идентификатор группы владельца (gid), реакции и маски, заданные на различные сигналы; и.т.п. g) Издания других запросов (системных вызовов) к операционной системе
("богу") для выполнения различных "внешних" операций. h) Все остальные действия происходят внутри процесса и никак не влияют на другие процессы и устройства ("миры"). В частности, один процесс НИКАК не может получить доступ к памяти другого процесса, если тот не позволил ему это явно (механизм shared memory); адресные пространства процессов независимы и изолированы (равно и пространство ядра изолировано от памяти процессов).
Операционная система выступает в качестве коммуникационной среды, связывающей "миры"-процессы, "миры"-внешние устройства (включая терминал пользователя); а также в качестве распорядителя ресурсов "Вселенной", в частности - времени (по очереди выделяемого активным процессам) и пространства (в памяти компьютера и на дисках).
Уже неоднократно упоминали "системные вызовы". Что же это такое? С точки зрения Си-программиста - это обычные функции. В них передают аргументы, они возвращают значения. Внешне они ничем не отличаются от написанных нами или библиотечных функций и вызываются из программ одинаковым с ними способом.
С точки же зрения реализации - есть глубокое различие. Тело функции- сисвызова расположено не в нашей программе, а в резидентной (т.е. постоянно находящейся в памяти компьютера) управляющей программе, называемой ядром операционной системы*.
Поведение всех программ в системе вытекает из поведения системных вызовов, которыми они пользуются. Даже то, что UNIX является многозадачной системой, непосредственно вытекает из наличия системных вызовов fork, exec, wait и спецификации их функционирования! То же можно сказать про язык Си - мобильность программы зависит в основном от набора используемых в ней библиотечных функций (и, в меньшей степени, от диалекта самого языка, который должен удовлетворять стандарту на язык Си). Если две разные системы предоставляют все эти функции (которые могут быть по-разному реализованы, но должны делать одно и то же), то программа будет компилироваться и работать в обоих системах, более того, работать в них одинаково.
Сам термин "системный вызов" как раз означает "вызов системы для выполнения действия", т.е. вызов функции в ядре системы. Ядро работает в привелегированном режиме, в котором имеет доступ к некоторым системным таблицам*, регистрам и портам внешних устройств и диспетчера памяти, к которым обычным программам доступ аппаратно запрещен (в отличие от MS DOS, где все таблицы ядра доступны пользовательским программам, что создает раздолье для вирусов). Системный вызов происходит в 2 этапа: сначала в пользовательской программе вызывается библиотечная функция-"корешок", тело которой написано на ассемблере и содержит команду генерации программного прерывания. Это - главное отличие от нормальных Си-функций - вызов по прерыванию. Вторым этапом является реакция ядра на прерывание:

1. переход в привелегированный режим;

2. разбирательство, КТО обратился к ядру, и подключение u-area этого процесса к адресному пространству ядра (context switching);

3. извлечение аргументов из памяти запросившего процесса;

4. выяснение, ЧТО же хотят от ядра (один из аргументов, невидимый нам - это номер системного вызова);

5. проверка корректности остальных аргументов;

6. проверка прав процесса на допустимость выполнения такого запроса;

7. вызов тела требуемого системного вызова - это обычная Си-функция в ядре;

8. возврат ответа в память процесса;

9. выключение привелегированного режима;
10. возврат из прерывания.
Во время системного вызова (шаг 7) процесс может "заснуть", дожидаясь некоторого события (например, нажатия кнопки на клавиатуре). В это время ядро передаст управление другому процессу. Когда наш процесс будет
"разбужен" (событие произошло) - он продолжит выполнение шагов системного вызова.
Большинство системных вызовов возвращают в программу в качестве своего значения признак успеха: 0 - все сделано, (-1) - сисвызов завершился неудачей; либо некоторое содержательное значение при успехе (вроде дескриптора файла в open(), и (-1) при неудаче. В случае неудачного завершения в предопределенную переменную errno заносится номер ошибки, описывающий причину неудачи (коды ошибок предопределены, описаны в include- файле и имеют вид Eчтото). Заметим, что при УДАЧЕ эта переменная просто не изменяется и может содержать любой мусор, поэтому проверять ее имеет смысл лишь в случае, если ошибка действительно произошла:

#include /* коды ошибок */ extern int errno; extern char *sys_errlist[]; int value; if((value = sys_call(...)) < 0 ){ printf("Error:%s(%d)n", sys_errlist[errno], errno ); exit(errno); /* принудительное завершение программы */

}
Предопределенный массив sys_errlist, хранящийся в стандартной библиотеке, содержит строки-расшифровку смысла ошибок (по-английски). Посмотрите описание функции per- ror().

Время в UNIX.

Ниже приведены примеры как узнавать время:
. В системе UNIX время обрабатывается и хранится именно в виде числа секунд; в частности текущее астрономическое время можно узнать системным вызовом

#include

#include time_t t = time(NULL); /* time(&t); */
Функция struct tm *tm = localtime( &t ); разлагает число секунд на отдельные составляющие, содержащиеся в int-полях структуры: tm_year год (надо прибавлять 1900) tm_yday день в году 0..365 tm_mon номер месяца 0..11 (0 - Январь) tm_mday дата месяца 1..31 tm_wday день недели 0..6 (0 - Воскресенье) tm_hour часы 0..23 tm_min минуты 0..59 tm_sec секунды 0..59
Номера месяца и дня недели начинаются с нуля, чтобы вы могли использовать их в качестве индексов: char *months[] = { "Январь", "Февраль", ..., "Декабрь" }; printf( "%sn", months[ tm->tm_mon ] );

Часто бывает нужда передавать значения времени в одной строке
Вот пример программы которая преобразовывает в ремя в такой формат:
/* Mon Jun 12 14:31:26 2000 */

#include

#include main() { /* команда date */ time_t t = time(NULL); char *s = ctime(&t); printf("%s", s);

}
UNIX-машины имеют встроенные таймеры (как правило несколько) с довольно высоким разрешением. Некоторые из них могут использоваться как "будильники" с обратным отсчетом времени: в таймер загружается некоторое значение; таймер ведет обратный отсчет, уменьшая загруженный счетчик; как только это время истекает - посылается сигнал процессу, загрузившему таймер.
Вот как, к примеру, выглядит функция задержки в микросекундах (миллионных долях секунды). Примечание: эту функцию не следует использовать вперемежку с функциями sleep и alarm.

#include

#include

#include

void do_nothing() {}

/* Задержка на usec миллионных долей секунды (микросекунд) */ void usleep(unsigned int usec) {

struct itimerval new, old;

/* struct itimerval содержит поля: struct timeval it_interval; struct timeval it_value;

Где struct timeval содержит поля: long tv_sec; -- число целых секунд long tv_usec; -- число микросекунд

*/ struct sigaction new_vec, old_vec;

if (usec == 0) return;

/* Поле tv_sec содержит число целых секунд.

Поле tv_usec содержит число микросекунд.

it_value - это время, через которое В ПЕРВЫЙ раз таймер "прозвонит", то есть пошлет нашему процессу сигнал SIGALRM.

Время, равное нулю, немедленно остановит таймер.

it_interval - это интервал времени, который будет загружаться в таймер после каждого "звонка"

(но не в первый раз).

Время, равное нулю, остановит таймер после его первого "звонка".

*/ new.it_interval.tv_sec = 0; new.it_interval.tv_usec = 0; new.it_value.tv_sec = usec / 1000000; new.it_value.tv_usec = usec % 1000000;

/* Сохраняем прежнюю реакцию на сигнал SIGALRM в old_vec, заносим в качестве новой реакции do_nothing()

*/ new_vec.sa_handler = do_nothing; sigemptyset(&new_vec.sa_mask); new_vec.sa_flags = 0;

sigaction(SIGALRM, &new_vec, &old_vec);

/* Загрузка интервального таймера значением new, начало отсчета.

* Прежнее значение спасти в old.

* Вместо &old можно также NULL - не спасать.

*/ setitimer(ITIMER_REAL, &new, &old);

/* Ждать прихода сигнала SIGALRM */ sigpause(SIGALRM);

/* Восстановить реакцию на SIGALRM */ sigaction(SIGALRM, &old_vec, (struct sigaction *) 0); sigrelse(SIGALRM);

/* Восстановить прежние параметры таймера */ setitimer(ITIMER_REAL, &old, (struct itimerval *) 0);

}

Пример оспользования интервалов

#include

#include /* _SC_CLK_TCK */

#include /* SIGALRM */

#include /* не используется */

#include /* struct tms */

struct tms tms_stop, tms_start; clock_t real_stop, real_start;

clock_t HZ; /* число ticks в секунде */

/* Засечь время момента старта процесса */ void hello(void){ real_start = times(&tms_start);

}

/* Засечь время окончания процесса */ void bye(int n){ real_stop = times(&tms_stop);

#ifdef CRONO

/* Разность времен */ tms_stop.tms_utime -= tms_start.tms_utime; tms_stop.tms_stime -= tms_start.tms_stime;

#endif

/* Распечатать времена */ printf("User time = %g seconds [%lu ticks]n", tms_stop.tms_utime / (double)HZ, tms_stop.tms_utime); printf("System time = %g seconds [%lu ticks]n", tms_stop.tms_stime / (double)HZ, tms_stop.tms_stime); printf("Children user time = %g seconds [%lu ticks]n", tms_stop.tms_cutime / (double)HZ, tms_stop.tms_cutime); printf("Children system time = %g seconds [%lu ticks]n", tms_stop.tms_cstime / (double)HZ, tms_stop.tms_cstime); printf("Real time = %g seconds [%lu ticks]n",

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25



2012 © Все права защищены
При использовании материалов активная ссылка на источник обязательна.