- •Операционные системы для программиста
- •Введение
- •1. Основные понятия
- •1.1. Понятие операционной системы
- •1.2. Системные соглашения для доступа к функциям ос
- •1.3. Особенности разработки программ в базовых ос
- •1.4. Командный интерфейс пользователя в ос
- •1.5. Информация об ошибках системной функции
- •2. Программный доступ к файловой системе
- •2.1. Понятия дескрипторов, идентификаторов и хэндлов
- •2.2. Ввод и вывод в стандартные файлы.
- •2.3. Базовые средства использования файлов
- •2.4. Многопользовательская блокировка файлов
- •2.5. Установка произвольной позиции в файле
- •3. Принципы построения ос
- •3.1. Модульная структура построения ос
- •3.2. Использование прерываний в ос
- •3.3. Управление системными ресурсами
- •3.4 Строение ядра операционной системы
- •3.5. Структура операционной системы типа Windows nt
- •4. Многофункциональный консольный вывод
- •4.1. Функции управления курсором
- •4.2. Многократный вывод символов и атрибутов
- •4.3. Вывод в произвольную позицию экрана
- •4.4. Ввод данных, размещенных предварительно на экране
- •5. Системные функции ввода для консольных устройств
- •5.1. Системные функции ввода текстовых строк
- •5.2. Событийно-управляемый ввод
- •5.3. Системные функции ввода с клавиатуры
- •5.4. Опрос ввода с клавиатуры в программе
- •5.5. Системные функции мыши для текстового режима
- •6. Файловые системы
- •6.1. Структуры файловых систем для пользователя
- •6.2. Методы распределения внешней памяти
- •6.3. Принципы построения файловых систем типа fat
- •6.4. Современные модификации файловой системы fat
- •6.5. Особенности построения файловой системы hpfs
- •6.6. Принципы построения файловой системы ntfs
- •6.7. Особенности строения файловых систем для Unix
- •6.8. Программный опрос файловой системы
- •7. Обеспечение множественности процессов
- •7.1. Основные понятия теории вычислительных процессов
- •7.2. Программное порождение процессов
- •7.3. Уничтожение процессов
- •7.4. Ожидание завершения процессов
- •8. Многопоточное функционирование ос
- •8.1. Понятие нити и связь Хе с процессом
- •8.2. Создание нитей (thread) в программе
- •8.3. Уничтожение нитей
- •8.4. Приостановка и повторный запуск нити
- •8.5. Ожидание завершения нити
- •9. Средства взаимодействия программных единиц
- •9.1. Абстрактные критические секции
- •9.2. Абстрактные семафоры
- •9.3. Семафоры взаимоисключения
- •9.4. Семафоры событий
- •9.5. Средства группового ожидания
- •9.6. Программные критические секции
- •9.7. Программные семафоры с внутренним счетчиком
- •10. Управление памятью
- •10.1. Виртуальная память
- •10.2. ЏодкРчка страниц для реализациШ виртуальной памяти
- •10.3. Системные функции распределения памяти
- •10.4. Совместное использование памяти
- •10.5. Отображение файлов в оперативную память
- •10.6. Динамически распределяемая память
- •11. Средства коммуникации процессов
- •11.1. Неименованные коммуникационные каналы Unix
- •11.2. Переназначение хэндлов для доступа к каналу
- •11.3. Неименованные каналы в Windows
- •11.4. Именованные каналы в Windows nt
- •11.5. Именованные каналы в Unix
- •12. Взаимодействие пользователя с ос
- •12.1. Интерфейсы операционных систем
- •12.2. Командные и операционные оболочки (shells)
- •12.3. Основные команды базовых операционных систем
- •12.4. Групповое выполнение и фоновый запуск команд
- •12.5. Стандартный ввод-вывод и конвейеры командной строки
- •12.6. Командные файлы и сценарии
- •Библиографический список
8.4. Приостановка и повторный запуск нити
Для нитей существует один вид системного действия, аналогов которому нет для процессов в операционных системах Windows и OS/2. Это – приостановка и повторный запуск отдельной нити. По смыслу действия одна из нитей процесса отдает приказ на приостановку другой нити этого же процесса. Приостановить нить другого процесса программным приказом невозможно (так как в подобном действии при внимательном анализе нет никакого практического смысла).
В операционной системе Unix для приостановки отдельной нити можно и нужно использовать уже знакомую читателю функцию pthread_kill со вторым параметром, задаваемым символической константой SIGSTOP, а для возобновления работы нити - ту же функцию, но уже с параметром SIGCONT. Следующий пример, представленный программой в листинге 8.4.1, демонстрирует приостановки и возобновление работы отдельной нити в операционной системе Unix, поддерживающей стандарт POSIX.
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
char lbuk[ ]="abcdefghijklmnoprstuwxyz";
pthread_t tid1, tid2, tid3;
void procthread1(void *arg)
{int k, j;
for (k=0; k<24; k++)
{printf("\033[%02d;20H",k+1);
printf("\033[1;34m");
for (j=0; j<(int)arg; j++)
printf("%c",lbuk[k]);
if (k= =5) {pthread_kill(tid2, SIGSTOP);
printf("-Suspend thread2");}
if (k= =11) {pthread_kill(tid2, SIGCONT);
printf("-Resume thread2");}
printf("\n"); usleep(800000);
}
}
void procthread2(void *arg)
{int k, j;
for (k=0; k<24; k++)
{printf("\033[%02d;40H",k+1);
printf("\033[1;32m");
for (j=0; j<(int)arg; j++)
printf("%c",lbuk[k]);
usleep(1300000);
}
}
void procthread3(void *arg)
{int k, j;
for (k=0; k<24; k++)
{printf("\033[%02d;60H",k+1);
printf("\033[1;31m");
for (j=0; j<(int)arg; j++)
printf("%c",lbuk[k]);
printf("\n");
usleep(1100000);
}
}
int main()
{int k;
int rc;
printf("\033[2J\n");
rc=pthread_create(&tid1, NULL, (void*)procthread1, (void*)2);
rc=pthread_create(&tid2, NULL, (void*)procthread2, (void*)3);
rc=pthread_create(&tid3, NULL, (void*)procthread3, (void*)4);
for (k=0; k<24; k++)
{printf("\033[%02d;1H",k+1); printf("\033[1;37m");
printf("%c++",lbuk[k]);
printf("\n"); usleep(1000000);
}
pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL);
printf("\033[0m");
return 0;
}
Листинг 8.4.1. Программа с приостановкой нитей для Unix
В этой программе первая нить на 5-м шаге своей работы отдает приказ приостановки второй нити (идентификатор которой в tid2). Второй нитью мы здесь называем нить с идентификатором tid2, работающую на основе процедуры procthread2, а главную нить условно считаем нулевой. Приказ такой приостановки выдается в виде
pthread_kill(tid2, SIGSTOP).
Сама первая нить после такого приказа продолжает работать, а вторая, как легко наблюдать на экране по выводимым результатам, временно ничего не выводит, будучи приостановленной. Далее на 11-м шаге работы первой нити – в процедуре procthread1 – вызывается функция возобновления работы приостановленной второй нити. Эта функция в программе присутствует в виде pthread_kill(tid2, SIGCONT). После ее выполнения, как можно наблюдать по выводу процесса, который работает по программе из листинга 8.4.1, вторая нить продолжает свой вывод, а следовательно, работает дальше. Небольшие дополнения в программе относительно ее аналога в листинге 8.2.1 осуществляют поясняющий вывод в ходе ее выполнения и предназначены для наглядности наблюдаемого процесса.
Программные средства для приостановки и возобновления нитей в операционных системах типа Windows состоят из двух функций ResumeThread и SuspendThread. Обе они имеют единственный аргумент – хэндл нити, на которую они должны подействовать – приостановить или возобновить ее работу. Прототипы этих функций описываются в виде:
DWORD SuspendThread(HANDLE hthread);
DWORD ResumeThread(HANDLE hthread).
Использование этих функций не имеет никаких особенностей в сравнении с другими рассмотренными операционными системами. В листинге 8.4.2 приведены фрагменты программы, отсутствующие части которой должны быть взяты из листинга 8.2.2 (начальная часть, тексты процедур procthread1, procthread2 и опущенные детали остальных). Эта программа создает три нити, кроме главной, и в ходе их работы в одной из них (третьей по условному счету) приостанавливает работу первой из них. Затем через несколько шагов внутреннего цикла в процедуре третьей нити отдается приказ на возобновление работы приостановленной ранее нити.
#include <windows.h>
#include <process.h>
. . .
DWORD WINAPI procthread3(void *arg)
{int k, j;
COORD pos;
for (k=0; k<24; k++) {
. . .
for (j=0; j<(int)arg; j++) printf("%c",lbuk[k]);
if (k==5)
{SuspendThread(hthread1);
pos.X=50; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);
printf("Suspend thread1 into step=5");
}
if (k==16)
{ResumeThread(hthread1);
pos.X=50; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);
printf("Resume thread1 into step=16");
}
. . .
Sleep(1000);
}
}
void main()
{unsigned long threadid1, threadid2, threadid3;
int k;
COORD pos;
hstdout=GetStdHandle(STD_OUTPUT_HANDLE);
. . .
for (k=0; k<24; k++) {
. . .
printf("%c++",lbuk[k]);
if (k==9)
{TerminateThread(hthread2, 0);
pos.X=1; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);
printf("Kill thread2");
}
LeaveCriticalSection(&csec);
Sleep(1500);
}
. . .
CloseHandle(hthread1); CloseHandle(hthread2); CloseHandle(hthread3);
}
Листинг 8.4.2. Фрагменты программа с уничтожением нитей для Windows
Заметим, что в программе для управления поведением нитей используются их хэндлы, но никак не используются идентификаторы нитей. Практически в Windows всегда заметна некоторая избыточность средств, которая частично оправдывается большой суммарной сложностью системы.
