Передача аргументов новым потокам

Передача аргументов новым потокам

Мы уже упомянули, что в листинге 26.2 мы преобразуем целочисленную переменную connfd к указателю на неопределенный тип (void), но этот способ не работает в некоторых системах. Для корректной обработки данной ситуации требуются дополнительные усилия.

В первую очередь, заметим, что мы не можем просто передать адрес connfd нового потока, то есть следующий код не будет работать:

int main(int argc, char **argv) {

 int listenfd, connfd;

 ...

 for (;;) {

  len = addrlen;

  connfd = Accept(listenfd, cliaddr, &len);

  Pthread_create(&tid, NULL, &doit, &connfd);

 }

}

static void* doit(void *arg) {

 int connfd;

 connfd = *((int*)arg);

 Pthread_detach(pthread_self());

 str_echo(connfd); /* та же функция, что и прежде */

 Close(connfd);    /* мы закончили с присоединенным сокетом */

 return(NULL);

}

С точки зрения ANSI С здесь все в порядке: мы гарантированно можем преобразовать целочисленный указатель к типу void* и затем обратно преобразовать получившийся указатель на неопределенный тип к целочисленному указателю. Проблема заключается в другом — на что именно он будет указывать?

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

? Функция accept возвращает управление, записывается новое значение переменной connfd (допустим, новый дескриптор равен 5) и в главном потоке вызывается функция pthread_create. Указатель на connfd (а не фактическое его значение!) является последним аргументом функции pthread_create.

? Создается новый поток, и начинает выполняться функция 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 [ <host> ] <service or port>");

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). Обычно это достигается с помощью некоторой разновидности синхронизации, осуществляемой внутри библиотечных функций и являющейся для нас прозрачной (то есть незаметной).

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Установка руководства по потокам Linux, вер. 2.2.5

Из книги Linux From Scratch автора Бикманс Герард

Установка руководства по потокам Linux, вер. 2.2.5 Приблизительное время компиляции: 0.01 SBU Необходимое дисковое пространство: 1.5 MBИнсталляция руководства по потокам Linux, вер. 2.2.5После распаковки glibc-linuxthreads будут созданы две директории. Войдите в директорию linuxthreads , не в


Тест «Стремление к новым играм»

Из книги Как справиться с компьютерной зависимостью автора Краснова С В

Тест «Стремление к новым играм» Предлагается на ряд вопросов ответить «да», «иногда», «нет».1. Можете ли вы завершить работу, если она вам не интересна?2. Преодолеваете ли вы внутреннее сопротивление, если требуется предпринять что-то неприятное?3. Оказываясь в


Семинар по новым возможностям

Из книги AutoCAD 2009 автора Орлов Андрей Александрович

Семинар по новым возможностям Как уже говорилось, семинар по новым возможностям – это мультимедийная презентация, в которой пользователи могут познакомиться с новыми возможностями программы AutoCAD. По умолчанию семинар запускается каждый раз при загрузке программы (см.


Путеводитель по новым процессорам AMD Олег Нечай

Из книги Цифровой журнал «Компьютерра» № 15 [03.05.2010 — 09.05.2010] автора Журнал «Компьютерра»

Путеводитель по новым процессорам AMD Олег Нечай После прорыва начала «нулевых» AMD благополучно вернулась в своё обычное состояние вечно догоняющего и, несмотря на довольно интересные и, бесспорно, передовые технические решения, даже не пытается


Путеводитель по новым процессорам AMD (часть 2) Олег Нечай

Из книги Цифровой журнал «Компьютерра» № 16 [10.05.2010 — 16.05.2010] автора Журнал «Компьютерра»

Путеводитель по новым процессорам AMD (часть 2) Олег Нечай Опубликовано 12 мая 2010 года Вторую часть нашей статьи о современных процессорах AMD мы построили так же, как и материал о чипах Intel Core i3/i5/i7: сначала мы приведём справочную информацию об основных


Путеводитель по новым мобильным процессорам Олег Нечай

Из книги Цифровой журнал «Компьютерра» № 17 [17.05.2010 — 23.05.2010] автора Журнал «Компьютерра»

Путеводитель по новым мобильным процессорам Олег Нечай Опубликовано 19 мая 2010 года Львиную долю рынка мобильных процессоров занимает, разумеется, продукция корпорации Intel – причём речь идёт не только о классических чипах для лэптопов Сore и Сeleron, но


Семинар по новым возможностям

Из книги AutoCAD 2010 автора Орлов Андрей Александрович

Семинар по новым возможностям Как уже говорилось, семинар по новым возможностям – это мультимедийная презентация, в которой пользователи могут познакомиться с новыми возможностями программы AutoCAD. По умолчанию семинар запускается каждый раз при загрузке программы (см.


Путеводитель по новым мобильным процессорам Олег Нечай

Из книги Цифровой журнал «Компьютерра» № 74 [20.06.2011 — 26.06.2011] автора Журнал «Компьютерра»

Путеводитель по новым мобильным процессорам Олег Нечай Опубликовано 21 июня 2011 года Как и год назад, большую часть рынка мобильных центральных процессоров занимает корпорация Intel с семейством чипов Core i3/i5/i7. Однако в современных ноутбуках под этим


Передача аргументов

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Передача аргументов Один из аспектов нотации требует разъяснений: что происходит со значениями, переданными в качестве аргументов подпрограмме?Рассмотрим вызов в формеr (a1, a2, ..., an)соответствующий программеr (x1: T1, x2: T2, ..., xn: Tn) is ...где r может быть как функцией, так и


Назад к процессам и потокам

Из книги Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform автора Кёртен Роб

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


Урок № 67. Передача собственных материалов в переработку на сторону и передача продукции из давальческого сырья

Из книги 1С: Бухгалтерия 8 с нуля. 100 уроков для начинающих автора Гладкий Алексей Анатольевич

Урок № 67. Передача собственных материалов в переработку на сторону и передача продукции из давальческого сырья В процессе производственной деятельности предприятия часто приходится осуществлять передачу собственных материалов стороннему переработчику для выпуска


Глава 2 С новым 1989 годом!

Из книги Интернет как иллюзия. Обратная сторона сети автора Морозов Евгений

Глава 2 С новым 1989 годом! История киберутопизма небогата событиями, но двадцать первое января 2010 года точно займет место в ее анналах (наряду, вероятно, с рассуждениями Эндрю Салливана о роли “Твиттера” в тегеранских событиях). В тот день госсекретарь Хиллари Клинтон