
- •1) Основные понятия в спо. Классификация ос. Функции ос. Схема состояний задачи в вс.
- •2)Вычислительный ресурс и схема его выделения. Многозадачный режим работы вс. Схема ос жрв, платформенные, встраиваемые. Общая структура ос (уровни ос )
- •3)Основные элементы пк. Регистры процессора. Схема и пример исполнения команд.
- •4)Прерывания. Аппаратные, программные пользовательские и системные. Схема обработки прерывания
- •6) Архитектура ос Windows. Среда разработки программного обеспечения ms Visual Studio.
- •7)Архитектура ос qnx. Операционная среда Photon ос qnx6. Схема каталогов фс unix
- •8) Среда разработки программного обеспечения ide Momentics
- •10) Процессы в qnx6: типы (системные, демоны, прикладные), атрибуты, управление (process.C, fork.C, exec.C, spawn.C).
- •11)Функции создания процесса (p2-1.Cc). Затраты на порождение и переключение процесса (p5.Cc).
- •12) Жизненный путь потока. Потоки в qnx6: атрибуты, состояния, управление, диспетчеризация. (p5t.Cc)
- •14) Функции создания потока. Затраты на порождение нового протока. Сигналы. (p2-2.Cc)
- •15) Взаимодействие процессов. Механизмы параллельных вычислений. Синхронизация в Windows. Синхронизация в qnx6. (shm_creator.C, shm_user.C)
- •16)Принципы планирования потоков. Диспетчеризация в Windows и qnx6. Инверсия приоритетов. (prio.C)
- •17) Принципы функционирования smp и кластеров (prio.C)
- •18) Управление памятью. Модели памяти: сегментная, страничная, сегментно-страничная. (shm_creator.C, shm_user.C)
- •19) Виртуальная память. Организация памяти в Windows и qnx6. (shm_creator.C, shm_user.C)
- •20) Файловые системы. Fat. Ntfs. Qnx4. Схема доступа к кластерам в fat16. (t1.Cc
- •21)Raid массивы. Устройства io. Io в Windows
- •21) Принципы построения и защиты от сбоев и несанкционированного доступа
11)Функции создания процесса (p2-1.Cc). Затраты на порождение и переключение процесса (p5.Cc).
Рассмотрим временные затраты на создание процесса с помощью функции fork() на примере программы p2-1.cc [17]:
//p2-1.cc
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <iostream.h>
#include <sys/neutrino.h>
#include <process.h>
#include <sys/syspage.h>
static double cycle2milisec ( uint64_t ccl ) {
const static double s2m = 1.E+3;
const static uint64_t cps = SYSPAGE_ENTRY( qtime )->cycles_per_sec;
// частота процессора:
return (double)ccl * s2m / (double)cps;
};
struct mbyte {
#pragma pack( 1 )
uint8_t data[ 1024 * 1024 ];
#pragma pack( 4 )
};
int main( int argc, char *argv[] ) {
mbyte *blk = NULL;
if( argc > 1 && atoi( argv[ 1 ] ) > 0 ) {
blk = new mbyte[ atoi( argv[ 1 ] ) ];
};
uint64_t t = ClockCycles();
pid_t pid = fork();
if( pid == -1 ) { perror( "fork" ); exit( EXIT_FAILURE );}
if( pid == 0 ) exit( EXIT_SUCCESS );
if( pid > 0 ) {
waitpid( pid, NULL, WEXITED );
t = ClockCycles() - t;
};
if( blk != NULL ) delete blk;
cout << "Fork time: " << cycle2milisec( t ) << " msec. [" << t << " cycles]" << endl;
exit( EXIT_SUCCESS );
};
Программа начинается с точки входа – функции main(). Предварительно задается структура mbyte, в которой задается блок данных размером один мегабайт. В главном потоке проверяется условие (argc > 1 && atoi( argv[ 1 ]) > 0 ), где функция atoi() преобразует символьную сстроку соответствующую первому параметру из командной строки в целое число ( argv[ 0 ] соответствует имени программы – p2-1). Если это значение больше нуля, то с помощью функции new() и структуры mbyte создается блок данных соответствующего размера. Затем с помощью функции ClockCycles() определяется в переменной t имеющей тип данных uint64_t текущее количество процессорных циклов, котрое необходимо для определения времни затрачиваемого на создание процесса.
Функция fork() создает дочерний процесс. Для дочернего процесса pid = 0 поэтому условие выполняется и дочерний процесс сразу же после проверки условия завершается функцией exit( EXIT_SUCCESS ). В это время родительский процесс ожидает завершения дочерненого порцесса на функции waitpid( pid, NULL, WEXITED ). Как только дочерний процесс завершится в переменной t = ClockCycles() - t определяется количество процессорных затраченных на порожденние процесса. Затем удаляется блок данных blk и осуществляется вывод на экран через поток вывода cout и с помощью функции cycle2milisec( t ), преобразующей процессорные циклы в секунды, время на создание и уничтожение процесса.
Интересны не только затраты на порождение нового процесса, но и то, насколько «эффективно» сосуществуют параллельные процессы в ОС, насколько быстро происходит переключение контекста с одного процесса на другой [17]. Для оценки этих затрат рассмотрим приложение р5.сс.
// P5.cc
#include <stdlib.h>
#include <inttypes.h>
#include <iostream.h>
#include <unistd.h>
#include <sched.h>
#include <sys/neutrino.h>
int main( int argc, char *argv[] ) {
unsigned long N = 1000;
if( argc > 1 && atoi( argv[ 1 ] ) > 0 ) N = atoi( argv[ 1 ] );
pid_t pid = fork();
if( pid == -1 ) cout << "fork error" << endl, exit( EXIT_FAILURE );
uint64_t t = ClockCycles();
for( unsigned long i = 0; i < N; i++ ) sched_yield();
t = ClockCycles() - t;
delay( 200 );
cout << pid << "\t: cycles - " << t << "; on sched - " << ( t / N ) / 2 << endl;
exit( EXIT_SUCCESS );
};
Программа начинается с точки входа – функции main(). Если при запуске программы в командной строке задано количество повторений цикла, то с помощью функци atoi() оно преобразуется в новое значение переменной N . Функция fork() создает дочерний процесс. И в дочернем и в родительском процессах (их главных потоках) определяются переменные t (своих для каждого процесса). Они имеют тип данных uint64_t и хранят текущее количество процессорных циклов, котрое необходимо для определения времни затрачиваемого на переключение контекста процессов.
В каждом из процессов (главных потоках) запускается N раз for-цикл, где выполняется единственная функция sched_yield(). Она переводит вызвавший ее процесс (главный поток) из состояния выполнения в состяние готовности к выполнению (хотя квант времени выделенный для работы этого потока еще не истек) и запускает передиспетчеризацию потоков.
После завершения цила каждый процесс (главный поток) определяет в своей переменной t = ClockCycles() - t количество процессорных циклов затраченных на выполнение. Делает задержку на 0,2 секунды и выводит на экран через поток вывода cout результаты своей работы. На рис.47 показано выполнение программы p5.cc в перспективе System Profiler.
Таким образом, здесь использована симметричная схема, где два одновременно выполняющихся процесса настолько симметричны и идентичны, что они даже не анализируют PID после выполнения fork(), они только в максимальном темпе «перепасовывают» друг другу активность. Рис. 48 показано взаимодействие двух идентичных процессов: вся их «работа» состоит лишь в том, чтобы как можно быстрее передать управление партнеру.