UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Функции, безопасные в многопоточной среде
Стандарт POSIX.1 требует, чтобы все определенные в нем функции, а также функции, определенные в стандарте ANSI С, были безопасными в многопоточной среде. Исключения из этого правила приведены в табл. 26.1.
К сожалению, в POSIX.1 ничего не сказано о безопасности в многопоточной среде по отношению к функциям сетевого API. Последние пять строк в этой таблице появились благодаря Unix 98. В разделе 11.18 мы говорили о том, что функции
gethostbyname
gethostbyaddr
_r
getXXX
Таблица 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 |
Приведенная таблица позволяет заключить, что общим способом сделать функцию допускающей повторное вхождение является определение новой функции с названием, оканчивающимся на
_r
26.5. Собственные данные потоков
При преобразовании существующих функций для использования в многопоточной среде часто возникают проблемы, связанные со статическими переменными. Функция, сохраняющая состояние в собственном буфере или возвращающая результат в виде указателя на статический буфер, не является безопасной в многопоточной среде, поскольку несколько потоков не могут использовать один и тот же буфер для хранения разных данных. Такая проблема имеет несколько решений.
1. Использование собственных данных потоков (thread-specific data). Это нетривиальная задача, и функция при этом преобразуется к такому виду, что может использоваться только в системах, поддерживающих потоки. Преимущество этого подхода заключается в том, что не меняется вызывающая последовательность, и все изменения связаны с библиотечной функцией, а не с приложениями, которые вызывают эту функцию. Позже в этом разделе мы покажем безопасную в многопоточной среде версию функции
readline
2. Изменение вызывающей последовательности таким образом, чтобы вызывающий процесс упаковывал все аргументы в некую структуру, а также записывал в нее статические переменные из листинга 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