Современные операционные системы

Современные операционные системы
Процессы и потоки / Вызов библиотечной процедуры

Вызов библиотечной процедуры




Когда поток завершает свою работу, выход из него может быть осуществлен за счет вызова библиотечной процедуры, к примеру thread_exit. После этого он прекращает свое существование и больше не фигурирует в работе планировщика. В некоторых использующих потоки системах какой-нибудь поток для осуществления выхода может ожидать выхода из какого-нибудь другого (указанного) потока после вызова процедуры, к примеру threadJoin. Эта процедура блокирует вызывающий поток до тех пор, пока не будет осуществлен выход из другого (указанного) потока. В этом отношении создание и завершение работы потока очень похоже на создание и завершение работы процесса, при использовании примерно одних и тех же параметров.

Другой распространенной процедурой, вызываемой потоком, является thread_ yield. Она позволяет потоку добровольно уступить центральный процессор для выполнения другого потока. Важность вызова такой процедуры обусловливается отсутствием прерывания по таймеру, которое есть у процессов и благодаря которому фактически задается режим многозадачности. Для потоков важно проявлять вежливость и добровольно время от времени уступать центральный процессор, чтобы дать возможность выполнения другим потокам. Другие вызываемые процедуры позволяют одному потоку ожидать, пока другой поток не завершит какую-нибудь работу, а этому потоку — оповестить о том, что он завершил определенную работу, и т. д.

Хотя потоки зачастую приносят пользу, они также вносят в модель программирования и ряд сложностей. Для начала рассмотрим эффект, возникающий при осуществлении системного вызова fork, принадлежащего ОС UNIX. Если у родительского процесса есть несколько потоков, должны ли они быть у дочернего процесса? Если нет, то процесс может неверно функционировать из-за того, что все они составляют его неотъемлемую часть.

Но если дочерний процесс получает столько же потоков, сколько их было у родительского процесса, что произойдет, если какой-нибудь из потоков родительского процесса был заблокирован системным вызовом read, используемым, к примеру, для чтения с клавиатуры? Будут ли теперь два потока, в родительском и в дочернем процессах, заблокированы на вводе с клавиатуры? Если будет набрана строка, получат ли оба потока ее копию? Или ее получит только поток родительского процесса? А может быть, она будет получена только потоком дочернего процесса? Сходные проблемы существуют и при открытых сетевых подключениях.

Другой класс проблем связан с тем, что потоки совместно используют многие структуры данных. Что происходит в том случае, если один поток закрывает файл в тот момент, когда другой поток еще не считал с него данные? Предположим, что один поток заметил дефицит свободной памяти и приступил к выделению дополнительного объема. На полпути происходит переключение потоков, и новый поток тоже замечает дефицит свободной памяти и приступает к выделению дополнительного объема. Вполне возможно, что дополнительная память будет выделена дважды. Для решения этих проблем следует приложить ряд усилий, но для корректной работы многопоточных программ требуется все тщательно продумать и спроектировать.



Полное описание: Вызов библиотечной процедуры




С этим описанием рассматриваются следующие темы:


Потоки в POSIX
Чтобы предоставить возможность создания переносимых многопоточных программ, в отношении потоков институтом IEEE был определен стандарт — IEEE standard 1003.1с. Определенный в нем пакет, касающийся потоков, называется Pthreads. Он поддерживается большинством UNIX-систем. В стандарте определено более 60 вызовов функций. Рассмотреть в этой книге такое количество функций мы не в состоянии. Лучше мы опишем ряд самых основных функций, чтобы дать вам представление о том, как они работают. В табл. 2.5 п ... Читать

Код процедуры thread_yield
Но у потоков есть одно основное отличие от процессов. Когда поток на время останавливает свое выполнение, например когда он вызывает thread_yield, код процедуры thread_yield может самостоятельно сохранять информацию о потоке в таблице потоков. Более того, он может затем вызвать планировщик потоков, чтобы тот выбрал для выполнения другой поток. Процедура, которая сохраняет состояние потока, и планировщик, — это всего лишь локальные процедуры, поэтому их вызов намного более эффективен, чем осущест ... Читать

Реализация потоков в ядре
Теперь давайте рассмотрим, что произойдет, если ядро будет знать о потоках и управлять ими. Как показано на рис. 2.10, б, здесь уже не нужна система поддержки исполнения программ. Также здесь нет и таблицы процессов в каждом потоке. Вместо этого у ядра есть таблица потоков, в которой отслеживаются все потоки, имеющиеся в системе. Когда потоку необходимо создать новый или уничтожить существующий поток, он обращается к ядру, которое затем производит создание или разрушение путем обновления таблицы ... Читать

Сигналы прерывания клавиатуры
Другие сигналы, например прерывания клавиатуры, не имеют определенного отношения к потокам. Кто их должен перехватывать? Один специально назначенный поток? Или все потоки? А может быть, заново создаваемый всплывающий поток? Кроме того, что произойдет, если один из потоков вносит изменения в обработчики сигналов, не уведомляя об этом другие потоки? А что случится, если одному потоку потребуется перехватить конкретный сигнал (например, когда пользователь нажмет CTRL-C), а другому потоку этот сигна ... Читать

Проблема с процедурами распределения памяти
Подобная проблема возникает и с процедурами распределения памяти, к примеру с процедурой malloc в UNIX, работающей с весьма важными таблицами использования памяти, например со связанным списком доступных участков памяти. Когда процедура malloc занята обновлением этих списков, они могут временно пребывать в несообразном состоянии, с указателями, которые указывают в никуда. Если в момент такого несообразного состояния произойдет переключение потоков и из другого потока поступит новый вызов, будут ... Читать