Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
■ Создается новый поток, и начинает выполняться функция doit
.
■ Готово другое соединение, и главный поток снова начинает выполняться (прежде, чем начнется выполнение вновь созданного потока). Завершается функция accept
, записывается новое значение переменной connfd
(например, значение нового дескриптора равно 6) и главный поток вновь вызывает функцию pthread_create
.
Хотя созданы два новых потока, оба они будут работать с одним и тем же последним значением переменной connfd
, которое, согласно нашему предположению, равно 6. Проблема заключается в том, что несколько потоков получают доступ к совместно используемой переменной (целочисленному значению, хранящемуся в connfd
) при отсутствии синхронизации. В листинге 26.2 мы решаем эту проблему, передавая значение переменной connfd
функции pthread_create
, вместо того чтобы передавать указатель на это значение. Этот метод работает благодаря тому способу, которым целочисленные значения в С передаются вызываемой функции (копия значения помещается в стек вызванной функции).
В листинге 26.3 показано более удачное решение описанной проблемы.
Листинг 26.3. Эхо-сервер TCP, использующий потоки с более переносимой передачей аргументов
//threads/tcpserv02.c
1 #include "unpthread.h"
2 static void *doit(void*); /* каждый поток выполняет эту функцию */
3 int
4 main(int argc, char **argv)
5 {
6 int listenfd, *iptr;
7 thread_t tid;
8 socklen_t addrlen, len;
9 struct sockaddr *cliaddr;
10 if (argc == 2)
11 listenfd = Tcp_listen(NULL, argv[1], &addrlen);
12 else if (argc == 3)
13 listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
14 else
15 err_quit("usage: tcpserv01 [ ] ");
16 cliaddr = Malloc(addrlen);
17 for (;;) {
18 len = addrlen;
19 iptr = Malloc(sizeof(int));
20 *iptr = Accept(listenfd, cliaddr, &len);
21 Pthread_create(&tid, NULL, &doit, iptr);
22 }
23 }
24 static void*
25 doit(void *arg)
26 {
27 int connfd;
28 connfd = *((int*)arg);
29 free(arg);
30 Pthread_detach(pthread_self());
31 str_echo(connfd); /* та же функция, что и раньше */
32 Close(connfd); /* мы закончили с присоединенным сокетом */
33 return (NULL);
34 }
17-22
Каждый раз перед вызовом функции accept
мы вызываем функцию malloc
и выделяем в памяти пространство для целочисленной переменной (дескриптора присоединенного сокета). Таким образом каждый поток получает свою собственную копию этого дескриптора.
28-29
Поток получает значение дескриптора присоединенного сокета, а затем освобождает занимаемую им память с помощью функции free
.
Исторически функции malloc
и free
не допускали повторного вхождения. Это означает, что при вызове той или иной функции из обработчика сигнала в то время, когда главный поток выполняет одну из них, возникает большая путаница, так как эти функции оперируют статическими структурами данных. Как же мы можем вызывать эти две функции в листинге 26.3? Дело в том, что в POSIX требуется, чтобы эти две функции, так же как и многие другие, были безопасными в многопоточной среде ( thread-safe ). Обычно это достигается с помощью некоторой разновидности синхронизации, осуществляемой внутри библиотечных функций и являющейся для нас прозрачной (то есть незаметной).
Функции, безопасные в многопоточной среде
Стандарт POSIX.1 требует, чтобы все определенные в нем функции, а также функции, определенные в стандарте ANSI С, были безопасными в многопоточной среде. Исключения из этого правила приведены в табл. 26.1.
К сожалению, в POSIX.1 ничего не сказано о безопасности в многопоточной среде по отношению к функциям сетевого API. Последние пять строк в этой таблице появились благодаря Unix 98. В разделе 11.18 мы говорили о том, что функции gethostbyname
и gethostbyaddr
не допускают повторного вхождения. Как уже отмечалось, некоторые производители определяют версии этих функций, обладающие свойством безопасности в многопоточной среде (их названия заканчиваются на _r
), но поскольку они не стандартизованы, лучше от них отказаться. Все функции getXXX
, не допускающие повторного вхождения, были приведены в табл. 11.5.
Таблица 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 показана новая структура и новые прототипы функций.
Читать дальшеИнтервал:
Закладка: