-->

UNIX: разработка сетевых приложений

На нашем литературном портале можно бесплатно читать книгу UNIX: разработка сетевых приложений, Стивенс Уильям Ричард-- . Жанр: ОС и Сети. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
UNIX: разработка сетевых приложений
Название: UNIX: разработка сетевых приложений
Дата добавления: 16 январь 2020
Количество просмотров: 381
Читать онлайн

UNIX: разработка сетевых приложений читать книгу онлайн

UNIX: разработка сетевых приложений - читать бесплатно онлайн , автор Стивенс Уильям Ричард

Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

Перейти на страницу:

Программирование с использованием потоков является параллельным (parallel), или одновременным (concurrent), программированием, так как несколько потоков могут выполняться параллельно (одновременно), получая доступ к одним и тем же переменным. Хотя ошибочный сценарий, рассмотренный нами далее, предполагает систему с одним центральным процессором, вероятность ошибки также присутствует, если потоки А и В выполняются в одно и то же время на разных процессорах в многопроцессорной системе. В обычном программировании под Unix мы не сталкиваемся с подобными ошибками, так как при использовании функции

fork
родительский и дочерний процессы не используют совместно ничего, кроме дескрипторов. Тем не менее мы столкнемся с ошибками этого типа при обсуждении совместного использовании памяти несколькими процессами.

Эту проблему можно с легкостью продемонстрировать на примере потоков. В листинге 26.11 показана программа, которая создает два потока, после чего каждый поток увеличивает некоторую глобальную переменную 5000 раз.

Мы повысили вероятность ошибки за счет того, что потребовали от программы получить текущее значение переменной

counter
, вывести это значение и записать его. Если мы запустим эту программу, то получим результат, представленный в листинге 26.10.

Листинг 26.10. Результат выполнения программы, приведенной в листинге 26.11

4: 1

4: 2

4: 3

4: 4

<i> продолжение выполнения потока номер 4</i>

4: 517

4: 518

5: 518 <i>теперь выполняется поток номер 5</i>

5: 519

5: 520

<i> продолжение выполнения потока номер 5</i>

5: 926

5: 927

4: 519 <i>теперь выполняется поток номер 4, записывая неверные значения</i>

4: 520

Листинг 26.11. Два потока, которые неверно увеличивают значение глобальной переменной

//threads/example01.c

 1 #include &quot;unpthread.h&quot;

 2 #define NLOOP 5000

 3 int counter; /* потоки должны увеличивать значение этой переменной */

 4 void *doit(void*);

 5 int

 6 main(int argc, char **argv)

 7 {

 8  pthread_t tidA, tidB;

 9  Pthread_create(&amp;tidA, NULL, &amp;doit, NULL);

10  Pthread_create(&amp;tidB, NULL, &amp;doit, NULL);

11  /* ожидание завершения обоих потоков */

12  Pthread_join(tidA, NULL);

13  Pthread_join(tidB, NULL);

14  exit(0);

15 }

16 void*

17 doit(void *vptr)

18 {

19  int i, val;

20  /* Каждый поток получает, выводит и увеличивает на

21   * единицу переменную counter NLOOP раз. Значение

22   * переменной должно увеличиваться монотонно.

23   */

24  for (i = 0; i &lt; NLOOP; i++) {

25   val = counter;

26   printf(&quot;%d: %dn&quot;, pthread_self(), val + 1);

27   counter = val + 1;

28  }

29  return (NULL);

30 }

Обратите внимание на то, что в первый раз ошибка происходит при переключении системы с выполнения потока номер 4 на выполнение потока номер 5: каждый поток в итоге записывает значение 518. Это происходит множество раз на протяжении 10 000 строк вывода.

Недетерминированная природа ошибок такого типа также будет очевидна, если мы запустим программу несколько раз: каждый раз результат выполнения программы будет отличаться от предыдущего. Также, если мы переадресуем вывод результатов в файл на диске, эта ошибка иногда не будет возникать, так как программа станет работать быстрее, что приведет к уменьшению вероятности переключения системы между потоками. Наибольшее количество ошибок возникнет в случае, если программа будет работать интерактивно, записывая результат на медленный терминал, но при этом также сохраняя результат в файл при помощи программы Unix

script
(которая описана в главе 19 книги [110]).

Только что описанная проблема, возникающая, когда несколько потоков изменяют значение одной переменной, является самой простой из проблем параллельного программирования. Для решения этой проблемы используются так называемые взаимные исключения (mutex — mutual exclusion), с помощью которых контролируется доступ к переменной. В терминах Pthreads взаимное исключение — это переменная типа

pthread_mutex_t
, которая может быть заблокирована и разблокирована с помощью следующих двух функций:

#include &lt;pthread.h&gt;

int pthread_mutex_lock(pthread_mutex_t *<i>mptr</i>);

int pthread_mutex_unlock(pthread_mutex_t *<i>mptr</i>);

<i>Обе функции возвращают: 0 в случае успешного выполнения, положительное значение Exxx в случае ошибки</i>

Если некоторый поток попытается блокировать взаимное исключение, которое уже блокировано каким-либо другим потоком (то есть принадлежит ему в данный момент времени), этот поток окажется заблокированным до освобождения взаимного исключения.

Если переменная-исключение размещена в памяти статически, следует инициализировать ее константой

PTHREAD_MUTEX_INITIALIZER
. В разделе 30.8 мы увидим, что если мы размещаем исключение в совместно используемой (разделяемой) памяти, мы должны инициализировать его во время выполнения программы путем вызова функции
pthread_mutex_init
.

Перейти на страницу:
Комментариев (0)
название