
Миргородская 7сессия / Операционные системы / %D0%9E%D0%A1_%D0%A1%D0%93%D0%A2%D0%A3%20v5
.pdfstruct interv { uint64_t s, f; }; interv *trtime;
void* threadfunc ( void* data ) {
// заблокироваться на барьере, чтоб соскочить с него одновременно pthread_barrier_wait( &bstart );
int id = pthread_self() - 2; trtime[ id ].s = ClockCycles(); workproc( (int)data ); trtime[ id ].f = ClockCycles();
pthread_barrier_wait( &bfinish ); return NULL;
};
int main( int argc, char *argv[] ) {
int opt, val, nthr = 1, nall = SHRT_MAX;
while ( ( opt = getopt( argc, argv, "t:n:p:a:" ) ) != -1 ) { switch( opt ) {
case 't' :
if( sscanf( optarg, "%i", &val ) != 1 ) perror( "parse command line failed" ), exit( EXIT_FAILURE );
if( val > 0 && val <= SHRT_MAX ) nthr = val; break;
case 'p' :
if( sscanf( optarg, "%i", &val ) != 1 ) perror( "parse command line failed" ), exit( EXIT_FAILURE );
if( val != getprio( 0 ) )
if( setprio( 0, val ) == -1 ) perror( "priority isn't a valid" ), exit( EXIT_FAILURE );
break; case 'n' :
if( sscanf( optarg, "%i", &val ) != 1 ) perror( "parse command line failed" ), exit( EXIT_FAILURE );
if( val > 0 ) nsingl *= val; break;
case 'a' :
if( sscanf( optarg, "%i", &val ) != 1 ) perror( "parse command line failed" ), exit( EXIT_FAILURE );
if( val > 0 ) nall = val; break;
default :
perror( "parse command line failed" ), exit( EXIT_FAILURE ); break;
}
};
151
if( nthr > 1 ) cout << "Multi-thread evaluation, thread number = " << nthr; else cout << "Single-thread evaluation";
cout << " , priority level: " << getprio( 0 ) << endl; _clockperiod clcout;
ClockPeriod( CLOCK_REALTIME, NULL, &clcout, 0 );
cout << "rescheduling = \t" << clcout.nsec * 4. / 1000000. << endl;
//калибровка единичного выполнения const int NCALIBR = 512;
uint64_t tmin = 0, tmax = 0; tmin = ClockCycles(); workproc( NCALIBR ); tmax = ClockCycles();
cout << "calculating = \t" << cycle2milisec ( tmax - tmin ) / NCALIBR << endl;
//многопотоковое выполнение
if( pthread_barrier_init( &bstart, NULL, nthr ) != EOK ) perror( "barrier init" ), exit( EXIT_FAILURE );
if( pthread_barrier_init( &bfinish, NULL, nthr + 1 ) != EOK ) perror( "barrier init" ), exit( EXIT_FAILURE );
trtime = new interv [ nthr ]; int cur = 0, prev = 0;
for( int i = 0; i < nthr; i++ ) {
cur = (int)floor( (double)nall / (double)nthr * ( i + 1 ) + .5 ); prev = (int)floor( (double)nall / (double)nthr * i + .5 );
if( pthread_create( NULL, NULL, threadfunc, (void*)( cur - prev ) ) != EOK ) perror( "thread create" ), exit( EXIT_FAILURE );
};
pthread_barrier_wait( &bfinish ); for( int i = 0; i < nthr; i++ ) {
tmin = ( i == 0 ) ? trtime[ 0 ].s : __min( tmin, trtime[ i ].s ); tmax = ( i == 0 ) ? trtime[ 0 ].f : __max( tmax, trtime[ i ].f );
};
cout << "evaluation = \t" << cycle2milisec ( tmax - tmin ) / nall << endl; pthread_barrier_destroy( &bstart );
pthread_barrier_destroy( &bfinish ); delete trtime;
exit( EXIT_SUCCESS );
};
Логика этого приложения крайне проста: есть некоторая продолжи-
тельная по времени рабочая функция (workproc), выполняющая массирован-
ные вычисления. Многократно (это число определяется ключом запуска а)
выполняется рабочая функция. Хорошо (то есть корректнее), если время ее
единичного выполнения, которое задается ключом p. В системе установлена
152

диспетчеризация по умолчанию - круговая, или карусельная). Весь объем этой работы делится поровну (или почти поровну) между несколькими (ключ t) потоками. На рис.53 показано выполнение программы t1.cc в перспективе
System Profiler.
Сравниваем усредненное время единичного выполнения рабочей функ-
ции для разного числа выполняющих потоков (в выводе "calculating" - это время эталонного вычисления в одном главном потоке, a "evaluation" - время того же вычисления, но во многих потоках). Для того чтобы иметь еще боль-
шую гибкость, предоставляется возможность переопределять приоритет, под которым в системе все это происходит (ключ р).
Рис.53. Выполнение программы t1.cc
153
Краткий итог этого теста может звучать так: при достаточно высоком уровне приоритета (выше 12-13, когда на его выполнение не влияют процес-
сы обслуживания клавиатуры, мыши и др.) время выполнения в «классиче-
ском» последовательном коде и в многопоточном коде (где несколько тысяч потоков!) практически не различаются. Различия не более 8%, причем в обе стороны.
Создание нового потока в программном коде осуществляет вызов: int pthread_create( pthread_t* thread,
const pthread_attr_t* attr,
void* (*start_routine)(void* ), void* arg );
где thread - NULL или указатель переменной типа pthread_t, значение которой будет загружено идентификатором созданного потока после успеш-
ного выполнения функции. Далее это значение (это и есть TID) может ис-
пользоваться по тексту программы для идентификации созданного потока, attr – NULL: если это значение NULL, то созданный поток будет иметь набор параметров, устанавливаемых по умолчанию. Если нет, то поток будет соз-
дан с параметрами, установленными в структуре attr. Start_routine - функция типа void* ()( void* ), функция потока; это тот код, который будет фактиче-
ски выполняться в качестве отдельного потока. arg - указатель на блок дан-
ных, передаваемых start.routine в качестве входного параметра. Вместе с од-
ним процессом функционируют и другие потоки процесса. В отличие от соз-
даваемых параллельных процессов, рассмотренных ранее, все потоки, созда-
ваемые в рамках одного процесса, разделяют единое адресное пространство процесса, и поэтому все переменные процесса, находящиеся в области види-
мости любого потока, доступны этому потоку.
154
3.6. Файловые системы QNX
Высокая степень отказоустойчивости благодаря разбиению блоков а основной битовой карте, защита от потерь данных и возможность быстрого восстановления, использование многопоточности, приоритетность. Родной раздел QNX называется QNX4FS (для версий ОС QNX 4.х – 6.3.) и QNX6FS (начиная с версии ОС QNX 6.4.0), новый раздел создается утилитой fdisk [15]. Принято согласование разделов - первое число порядковый номер диска, второе – тип раздела диска. Раздел имеет компоненты: блок загрузки,
ключевой (root), битовая карта, корневой каталог. Блок загрузчика - первич-
ный физический блок в разделе диска. Содержит начальный загрузчик. Кор-
невой блок имеет структуру обычного, содержит следующие в себе: корне-
вой root каталог, файл /.inodes – информационный узел. Если имя файла длиннее 16 символов, содержимое файла помещается в этот файл. Файл
/.boot содержит загрузочный образ ОС. Файл /.altboot - содержит резервный загрузочный образ. Файл /.longfilenames – файл, содержащий столько битов,
сколько разделов у диска. Каждому физическому разделу соответствует 1
бит.
Типы файлов.
В QNX файл - это объект, в который может производиться запись, из которого может производиться чтение, либо и то и другое. QNX поддержива-
ет шесть типов файлов: В QNX поддерживаются следующие типы файлов:
регулярные(обычные) файлы;
каталоги; жёсткие и символические ссылки;
блок- и байт-ориентированные специальные файлы;
специальные именованные устройства (Named Special Device);
именованные программные каналы (pipes).
Регулярные файлы - состоят из последовательности байт с произволь-
ным доступом и не имеют предопределенной структуры. Они составляют
155
большинство файлов в файловых системах. Файловые системы поддержи-
ваются Менеджером файловой системы и реализованы на базе блок-
ориентированных файлов, соответствующих разделам диска.
Каталоги - содержат элементы каталога и информацию, необходимую для поиска регулярных файлов; также содержат статус и атрибуты для каж-
дого регулярного файла. Каждый элемент каталога увязывает имя файла с файлом. Имя файла - это символьное имя, которое позволяет идентифициро-
вать файл и работать с ним. Файл может быть идентифицирован несколькими именами.
Символические связи (ссылки) - содержат путь к файлу или каталогу, к
которым перенаправляются все запросы; символические связи, часто исполь-
зуются для предоставления множества путей к одному файлу.
Программные каналы (pipes) и FIFO - служат как каналы ввода/вывода между взаимодействующими процессами.
Блок-ориентированные файлы - относятся к устройствам, таким, как диски, ленты и разделы дисков. Доступ к этим файлам обычно осуществля-
ется таким образом, что аппаратные характеристики устройств скрыты от приложений.
Байт-ориентированные специальные файлы-файлы, аналогичные блоч-
ным устройствам, с той разницей ,что символьные устройства обеспечивают интерфейс к аппаратуре, осуществляющей посимвольный ввод/вывод. К та-
кой аппаратуре относятся, например, последовательный порт, сетевая карта и т.п. Эти файлы ,так же как и блочные. Создаются драйверами при запуске.
Жесткие ссылки (связи) - дополнительные элементы каталога. При ее создании, во-первых, информация о физическом размещении данных выно-
сится в файл /.inodes, во-вторых, счетчик ссылок (атрибут файла) увеличива-
ется на единицу. При удалении одной из жестких ссылок реально будет уда-
лен только соответствующий элемент каталога, а счетчик ссылок на inode-
запись будет уменьшен на единицу. Как только счетчик достигнет значения
“ноль”, и inode-запись ,и физические данные файла будут уничтожены.
156
Именованные специальные устройства-специальный дополнительный тип файлов (Named Special Device).
В QNX файл может обозначаться более чем одним именем. Каждое имя файла называется связью. В действительности существует два вида связей:
жесткие связи, или просто "связи", и символические связи. Для поддержки связей каждого файла, имя файла отделяется от остальной информации, опи-
сывающей файл. Эта информация хранится в структуре, называемой inode
(индексным дескриптором).
Если файл имеет только одну связь (т.е. одно имя), то блок inode хра-
нится в элементе каталога для этого файла. Но если файл имеет более чем одну связь, то inode хранится как запись в специальном файле /.inodes, а
элемент каталога для файла содержит указатель на запись inode.Можно соз-
дать связь для файла, только если файл исвязь находятся в одной и той же файловой системе.
Нельзя создавать жесткие связи для каталога. Однако каждый каталог имеет две жестко определенные связи: «.» («точка»), «..» («точка точка»).
Имя файла "точка" соответствует текущему каталогу; "точка точка" соответ-
ствует каталогу, предшествующему текущему каталогу.
Доступ к регулярным файлам и каталогам управляется битами режима,
хранящимися в inode (индексном дескрипторе) файла. Эти биты разрешают чтение, запись и выполнение в зависимости от эффективных ID пользователя
игруппы. При этом пользователи делятся на три категории:
владелец файла;
члены группы, к которой принадлежит владелец;
остальные.
Процесс может выполняться с ID пользователя или ID группы файла, а
не родительского процесса. Механизм, который позволяет это, называется setuid (установить ID пользователя) и setgid (установить ID группы).
157

QNX может работать со следующими типами файловых систем:
1) встраиваемые: образная (ROM/Flash, Execute-in-place), в ОЗУ (вре-
менное хранилище), NOR Flash (линейное flash-ППЗУ), NAND Flash (стра-
ничное flash-ППЗУ);
2)дисковые: OC QNX (POSIX (QNX4)), Linux (Ext2), MS-DOS (FAT 12, 16, 32), CD-ROM (ISO9660, Joliet);
3)специальные: со сжатием (разворачивание «на лету»), пакетная (об-
новления и откаты на «лету»);
4) сетевые: NFS (совместимость с UNIX), CIFS ( совместимость Microsoft).
На рис. 54 показана типовая структура каталогов QNX Neutino. Основ-
ные каталоги следующие [5]:
Рис. 54 Организация каталогов QNX Neutino
Корневой каталог "/" является основой любой файловой системы
UNIX. Все остальные файлы и каталоги располагаются в рамках структуры,
158
порожденной корневым каталогом, независимо от их физического местона-
хождения.
/bin В каталоге /bin находятся наиболее часто употребляемые команды
иутилиты системы, как правило, общего пользования.
/dev Каталог /dev содержит специальные файлы устройств, являю-
щиеся интерфейсом доступа к периферийным устройствам.
/etc В этом каталоге находятся системные конфигурационные файлы и многие утилиты администрирования.
/lib В каталоге /lib находятся библиотечные файлы языка С и других языков программирования.
/lost+found Каталог "потерянных" файлов. Программы проверки и вос-
становления файловой системы помещают файлы в каталог /lost+found под системными числовыми именами.
/mnt Стандартный каталог для временного связывания (монтирования)
физических файловых систем к корневой для получения единого дерева ло-
гической файловой системы.
/home Общеупотребительный каталог для размещения домашних ка-
талогов пользователей.
/usr В этом каталоге находятся подкаталоги различных сервисных под-
систем -системы печати, электронной почты и т. д. (/usr/spool), исполняемые файлы утилит UNIX (/usr/bin), дополнительные программы, используемые на данном компьютере (/usr/Iocal), файлы заголовков (/usr/include), электрон-
ные справочники (/usr/man)n т. д.
/var В UNIX System V этот каталог является заменителем каталога
/usr/spool, используемого для хранения временных файлов различных сер-
висных подсистем — системы печати, электронной почты и т. д.
-/tmp Каталог хранения временных файлов, необходимых для работы различных подсистем QNX.
159

3.7. Инсталляция и последовательность загрузки QNX
Последовательность начального запуска
Как и большинство операционных систем, ОСРВ QNX Neutrino имеет несколько этапов загрузки (рис. 55).
Рис. 55. Процесс начальной загрузки QNX Neutrino
Ниже следует краткое описание каждого этапа [20].
ФАП (фазовая автоподстройка, phased locked loop, PLL). ФАП – это
процесс, длящийся от подачи питания на процессор до начала выполнения процессором первой инструкции. Для большинства ЦПУ процесс ФАП зани-
мает время, за которое исходная тактовая частота задающего генератора про-
ходит через все таймеры, используемые кристаллом. Время, занимаемое про-
цессом ФАП для получения необходимых частот, обычно соответствует наи-
большей временной метке, требуемой для запуска процессора. Время этапа ФАП не зависит от загружаемой ОС и меняется в зависимости от типа ЦПУ.
В некоторых случаях это время может быть более 32 мс.
НЗ (начальный загрузчик, initial program loader, IPL). IPL находит загрузочный образ ОС (OS image - это не ядро) и отдает управление про-
грамме загрузки, которая находится в этом образе. В QNX используется стан-
дартный начальный загрузчик, который выполняет минимально необходи-
мые операции для подготовки памяти, инициализации выбора нужных мик-
росхем и конфигурирования других, необходимых для работы ЦПУ устано-
вок. После окончания этих установок начальный загрузчик копирует в ОЗУ
160