Операционные системы "тонких" клиентов
Методическое пособие - Компьютеры, программирование
Другие методички по предмету Компьютеры, программирование
и нити. Созданная таким образом нить еще не выполняется. Она может быть запущена на выполнение системным вызовом resume_thread() или wait_for_thread(). В первом случае нить-потомок выполняется асинхронно, то есть, параллельно с нитью, ее породившей. Второй случай - синхронный запуск, выполнение породившей нити приостанавливается до завершения нити-потомка.
Мы говорим о нитях - родителе и потомке, однако на самом деле родственные отношения между порождающей и порожденной нитью весьма слабы. Системный вызов spawn_thread() возвращает нити-родителю идентификатор нити-потомка, но не обеспечивает наследования никаких ресурсов, кроме общих для всей команды. Нити выполняются независимо друг от друга, и выполнение нити-потомка продолжается даже после завершения родительской нити. Теоретически, даже завершение нити, в которой выполняется функция main(), не приводит к завершению всех порожденных ею нитей. Но именно нити main выделяются общие для всей команды статические объекты и ресурсы ввода-вывода, так что завершение нити main скорее всего приведет к аварийному завершению остальных нитей команды.
При создании нити ей может быть дано имя. Другая нить, желающая обратиться к данной, независимо от того, находится она в этой же команде или в другой, может использовать системный вызов find_thread(), который по имени нити возвращает ее идентификатор. Но идентификатор нити является уникальным во всей системе, а имя нити - не уникально. Вызов find_thread() возвращает идентификатор первой найденной нити с таким именем. Поэтому более надежным способом получения идентификатора нити является передача его нити-корреспонденту через глобальные переменные, параметры, средства взаимодействия и т.п.
Все нити выполняются параллельно, разделяя процессор (или процессоры) в соответствии с приоритетами. Приоритеты со значениями от 1 до 99 составляют класс приоритетов разделения времени, приоритеты со значениями 100 и выше - класс приоритетов реального времени.
Приоритеты разделения времени относительные - нити с такими приоритетами выполняются в режиме квантования времени с размером кванта 3 мсек. Приоритет определяет частоту получения кванта нитью. Нить, получившая квант, использует процессор до исчерпания ею кванта или до перехода в ожидание по собственной инициативе, или до появления нити с приоритетом реального времени. Нити разделения времени не вытесняют друг друга.
Приоритеты реального времени абсолютные. Когда нить с приоритетом реального времени приходит в состояние готовности, она немедленно вытесняет с процессора нить с приоритетом разделения времени или нить с более низким приоритетом реального времени.
Приоритеты являются статическими: они задаются при создании нити и не изменяются в дальнейшем.
Нить может до некоторой степени управлять своим планированием, переходя в состояние приостанова на заданный интервал времени (системный вызов snooze()) или завершаясь (системный вызов exit_thread()).
Управление нитью "со стороны" - из другой нити, которой известен идентификатор управляемой, возможно следующее:
нить может быть приостановлена системным вызовом suspend_thread(), а затем вновь запущена на выполнение системным вызовом resume_thread() или wait_for_thread().
для запуска заблокированной или "спящей" нити может быть использован системный вызов POSIX send_signal(). Сигнал SIGCONT разблокирует нить.
системный вызов kill_thread() прекращает выполнение нити.
9.3 Средства взаимодействия
При создании каждой нити для нее создается буфер сообщения. Другая нить, знающая идентификатор нити-корреспондента, может записать в этот буфер сообщение системным вызовом send_data(), а нить - владелец буфера выбирает сообщение системным вызовом recive_data(). Однако буфер рассчитан только на одно сообщение, а попытки писать данные в занятый буфер или выбирать данные из пустого буфера приводят к блокировке нити.
Более гибким средством обмена данными между нитями является порт (port). Следует отметить, что порт не является прямым аналогом ни одного из средств взаимодействия процессов, рассмотренных нами в главе 9 части I. Порт представляет собой общесистемную очередь сообщений, работающую по дисциплине "первым пришел - первым вышел". В системе может быть создано сколько угодно портов. Любая нить из любой команды, которой известен идентификатор порта, может записать в порт сообщение (системный вызов write_port()) и прочитать из порта сообщение (системный вызов read_port()). При создании порта (системный вызов create_port()) задается его емкость - число сообщений, которое может сохраняться в порте. Попытка писать в переполненный порт или читать из пустого порта, естественно, приводит к блокировке нити. Однако, есть варианты системных вызовов (write_port_etс() и read_port_etc()), которые к блокировке не приводят. Но система поддерживает общий репозиторий портов, емкость которого равна суммарной емкости всех созданных портов, и переполнение происходит только при заполнении общей емкости.
Порт принадлежит команде, в которой он был создан. Однако, если идентификатор порта, возвращаемый системным вызовом create_port(), передается в другую команду, эта другая команда также может использовать порт. Системный вызов delete_port() уничтожает порт, системный вызов close_port() закрывает порт для записи, но оставляет возможность прочитать сообщения, еще остающиеся в порте. Порт автоматически уничтожается, когда завершается последняя нить команды, в которой он был создан. Однако создавшая порт команда может передать право владения портом другой команде сис