UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Некоторые системы (например, Solaris) определяют константу PTHREAD_MUTEX_INITIALIZER как 0. Если данная инициализация будет опущена, это ни на что не повлияет, так как статически размещаемые переменные все равно автоматически инициализируются нулем. Но для других систем такой гарантии дать нельзя — например, в Digital Unix константа инициализации ненулевая.
В листинге 26.12 приведена исправленная версия листинга 26.11, в которой используется одно взаимное исключение для блокирования счетчика при работе с двумя потоками.
Листинг 26.12. Исправленная версия листинга 26.11, использующая взаимное исключение для защиты совместно используемой переменной
//threads/examplе01.с
1 #include "unpthread.h"
2 #define NLOOP 5000
3 int counter; /* увеличивается потоками */
4 pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
5 void *doit(void*);
6 int
7 main(int argc, char **argv)
8 {
9 pthread_t tidA, tidB;
10 Pthread_create(&tidA, NULL, &doit, NULL);
11 Pthread_create(&tidB, NULL, &doit, NULL);
12 /* ожидание завершения обоих потоков */
13 Pthread_join(tidA, NULL);
14 Pthread_join(tidB, NULL);
15 exit(0);
16 }
17 void*
18 doit(void *vptr)
19 {
20 int i, val;
21 /*
22 * Каждый поток считывает, выводит и увеличивает счетчик NLOOP раз.
23 * Значение счетчика должно возрастать монотонно.
24 */
25 for (i = 0; i < NLOOP; i++) {
26 Pthread_mutex_lock(&counter_mutex);
27 val = counter;
28 printf(%d: %dn", pthread_self(), val + 1);
29 counter = val + 1;
30 Pthread_mutex_unlock(&counter_mutex);
31 }
32 return(NULL);
33 }
Мы объявляем взаимное исключение с именем
counter_mutex
Насколько серьезной является дополнительная нагрузка, связанная с использованием взаимных исключений? Мы изменили программы, приведенные в листингах 26.11 и 26.12, заменив значение
NLOOP
/dev/null
26.8. Условные переменные
Взаимное исключение позволяет предотвратить одновременный доступ к совместно используемой (разделяемой) переменной, но для того чтобы перевести поток в состояние ожидания (спящее состояние) до момента выполнения некоторого условия, необходим другой механизм. Продемонстрируем сказанное на следующем примере. Вернемся к нашему веб-клиенту из раздела 26.6 и заменим функцию Solaris
thr_join
pthread_join
pthread_join
int ndone; /* количество потоков, завершивших выполнение */
pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;
Затем мы требуем, чтобы каждый поток по завершении своего выполнения увеличивал этот счетчик на единицу, используя соответствующее взаимное исключение.
void* do_get_read(void *vptr) {
...
Pthread_mutex_lock(&ndone_mutex);
ndone++;
Pthread_mutex_unlock(&ndone_mutex);
return(fptr); /* завершение выполнения потока */
}
Но каким при этом получается основной цикл? Взаимное исключение должно быть постоянно блокировано основным циклом, который проверяет, какие потоки завершили свое выполнение.
while (nlefttoread > 0) {
while (nconn < maxnconn && nlefttoconn > 0) {
/* находим файл для чтения */
...
}
/* Проверяем, не завершен ли поток */
Pthread_mutex_lock(&ndone_mutex);
if (ndone > 0) {
for (i =0; i < nfiles; i++) {
if (file[i].f_flags & F_DONE) {
Pthread_join(file[i].f_tid, (void**)&fptr);
/* обновляем file[i] для завершенного потока */
...
}
}