UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Функции, безопасные в многопоточной среде
Стандарт POSIX.1 требует, чтобы все определенные в нем функции, а также функции, определенные в стандарте ANSI С, были безопасными в многопоточной среде. Исключения из этого правила приведены в табл. 26.1.
К сожалению, в POSIX.1 ничего не сказано о безопасности в многопоточной среде по отношению к функциям сетевого API. Последние пять строк в этой таблице появились благодаря Unix 98. В разделе 11.18 мы говорили о том, что функции
gethostbynamegethostbyaddr_rgetXXXТаблица 26.1. Функции, безопасные в многопоточной среде
| Могут не быть безопасными в многопоточной среде | Должны быть безопасными в многопоточной среде | Комментарии |
|---|---|---|
| Asctime | asctime_r | Безопасна в многопоточной среде только в случае непустого аргумента |
| ctermid | ||
| Ctime | ctime_r | |
| getc_unlocked | ||
| getchar_unlocked | ||
| Getgrid | getgrid_r | |
| Getgrnam | getgrnam_r | |
| Getlogin | getlogin_r | |
| Getpwnam | getpwnam_r | |
| Getpwuid | getpwuid_r | |
| Gmtime | gmtime_r | |
| Localtime | localtime_r | |
| putc_unlocked | ||
| putchar_unlocked | ||
| Rand | rand_r | |
| Readdir | readdir_r | |
| Strtock | strtock_r | |
| tmpnam | Безопасна в многопоточной среде только в случае непустого аргумента | |
| Ttyname | ttyname_r | |
| GethostXXX | ||
| GetnetXXX | ||
| GetprotoXXX | ||
| GetservXXX | ||
| inet_ntoa |
Приведенная таблица позволяет заключить, что общим способом сделать функцию допускающей повторное вхождение является определение новой функции с названием, оканчивающимся на
_r26.5. Собственные данные потоков
При преобразовании существующих функций для использования в многопоточной среде часто возникают проблемы, связанные со статическими переменными. Функция, сохраняющая состояние в собственном буфере или возвращающая результат в виде указателя на статический буфер, не является безопасной в многопоточной среде, поскольку несколько потоков не могут использовать один и тот же буфер для хранения разных данных. Такая проблема имеет несколько решений.
1. Использование собственных данных потоков (thread-specific data). Это нетривиальная задача, и функция при этом преобразуется к такому виду, что может использоваться только в системах, поддерживающих потоки. Преимущество этого подхода заключается в том, что не меняется вызывающая последовательность, и все изменения связаны с библиотечной функцией, а не с приложениями, которые вызывают эту функцию. Позже в этом разделе мы покажем безопасную в многопоточной среде версию функции
readline2. Изменение вызывающей последовательности таким образом, чтобы вызывающий процесс упаковывал все аргументы в некую структуру, а также записывал в нее статические переменные из листинга 3.12. Это также было сделано, и в листинге 26.4 показана новая структура и новые прототипы функций.
Листинг 26.4. Структура данных и прототип функции для версии функции readline, допускающей повторное вхождение
typedef struct { int read_fd; /* дескриптор, указывающий, откуда считываются данные */ char *read_ptr; /* буфер, куда передаются данные */ size_t read_maxlen; /* максимальное количество байтов, которое может быть считано */ /* следующие три элемента для внутреннего использования функцией */ int rl_cnt; /* инициализируется нулем */ char *rl_bufptr; /* инициализируется значением rl_buf */ char rl_buf[MAXLINE];} Rline;void readline_rinit(int, void*, size_t, Rline*);ssize_t readline_r(Rline*);ssize_t Readline_r(Rline*);Эти новые функции могут использоваться как в системах с поддержкой потоков, так и в тех, где потоки не поддерживаются, но все приложения, вызывающие функцию
readline
