Стоимость функции
fork
довольно высока, так как при ее использовании требуется скопировать все содержимое памяти из родительского процесса в дочерний, продублировать все дескрипторы и т.д. Текущие реализации используют технологию, называемую
fork
остается высокой.Для передачи данных между родительским и дочерним процессами
fork
требуется использовать средства взаимодействия процессов (IPC). Передача информации перед вызовом
fork
не вызывает затруднений, так как при запуске дочерний процесс получает от родительского копию пространства данных и копии всех родительских дескрипторов. Но возвращение информации из дочернего процесса в родительский требует большей работы.Обе проблемы могут быть разрешены путем использования
Все потоки одного процесса совместно используют его глобальные переменные, поэтому им легко обмениваться информацией, но это приводит к необходимости синхронизации.
Однако общими становятся не только глобальные переменные. Все потоки одного процесса разделяют:
инструкции процесса;
большую часть данных;
открытые файлы (например, дескрипторы);
обработчики сигналов и вообще настройки для работы с сигналами (действие сигнала);
текущий рабочий каталог;
идентификаторы пользователя и группы пользователей.
У каждого потока имеются собственные:
идентификатор потока;
набор регистров, включая счетчик команд и указатель стека;
стек (для локальных переменных и адресов возврата);
переменная
errno
;маска сигналов;
приоритет.
Как сказано в разделе 11.18, можно рассматривать обработчик сигнала как некую разновидность потока. В традиционной модели Unix у нас имеется основной поток выполнения и обработчик сигнала (другой поток). Если в основном потоке в момент возникновения сигнала происходит корректировка связного списка и обработчик сигнала также пытается изменить связный список, обычно начинается путаница. Основной поток и обработчик сигнала совместно используют одни и те же глобальные переменные, но у каждого из них имеется свой собственный стек.
В этой книге мы рассматриваем потоки POSIX, которые также называются
pthread_
. Эта глава является введением в концепцию потоков, необходимым для того, чтобы в дальнейшем мы могли использовать потоки в наших сетевых приложениях. Более подробную информацию вы можете найти в [15].26.2. Основные функции для работы с потоками: создание и завершение потоков
В этом разделе мы рассматриваем пять основных функций для работы с потоками, а в следующих двух разделах мы используем эти функции для написания потоковой модификации клиента и сервера TCP.
Функция pthread_create
Когда программа запускается с помощью функции
exec
, создается один поток, называемый
pthread_create
.#include pthread.h
int pthread_create(pthread_t*
void *(*
Каждый поток процесса обладает собственным
pthread_t
(как правило, это
unsigned int
). При успешном создании нового потока его идентификатор возвращается через указатель
tid
.