26.9. Веб-клиент и одновременный доступ

26.9. Веб-клиент и одновременный доступ

Изменим код нашего веб-клиента из раздела 26.6: уберем вызов функции Solaris thr_join и заменим его вызовом функции pthread_join. Как сказано в разделе 26.6, теперь нам нужно точно указать, завершения какого потока мы ждем. Для этого мы используем условную переменную, описанную в разделе 26.8.

Единственным изменением в отношении глобальных переменных (см. листинг 26.7) является добавление нового флага и условной переменной:

#define F_JOINED 8 /* количество потоков */

int ndone; /* количество завершившихся потоков */

pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t ndone_cond = PTHREAD_COND_IINITIALIZER;

Единственным изменением функции do_get_read (см. листинг 26.9) будет увеличение на единицу значения переменной ndone и оповещение главного цикла о завершении выполнения потока:

 printf("end-of-file on %s ", fptr->f_name);

 Close(fd);

 Pthread_mutex_lock(&ndone_mutex);

 fptr->f_flags = F_DONE; /* сбрасывает флаг F_READING */

 ndone++;

 Pthread_cond_signal(&ndone_cond);

 Pthread_mutex_unlock(&ndone_mutex);

 return(fptr); /* завершение выполнения потока */

}

Большинство изменений касается главного цикла, представленного в листинге 26.8. Новая версия показана в листинге 26.13.

Листинг 26.13. Основной рабочий цикл функции main

//threads/web03.c

43  while (nlefttoread > 0) {

44   while (nconn < maxnconn && nlefttoconn > 0) {

45    /* находим файл для считывания */

46    for (i = 0; i < nfiles; i++)

47     if (file[i].f_flags == 0)

48      break;

49    if (i == nfiles)

50     err_quit("nlefttoconn = %d but nothing found", nlefttoconn);

51    file[i].f_flags = F_CONNECTING;

52    Pthread_create(&tid, NULL, &do_get_read, &file[i]);

53    file[i].f_tid = tid;

54    nconn++;

55    nlefttoconn--;

56   }

57   /* Ждем завершения выполнения одного из потоков */

58   Pthread_mutex_lock(&ndone_mutex);

59   while (ndone == 0)

60    Pthread_cond_wait(&ndone_cond, &ndone_mutex);

61   for (i = 0; i < nfiles; i++) {

62    if (file[i].f_flags & F_DONE) {

63     Pthread_join(file[i].f_tid, (void**)&fptr);

64     if (&file[i] != fptr)

65      err_quit("file[i] != fptr");

66     fptr->f_flags = F_JOINED; /* clears F_DONE */

67     ndone--;

68     nconn--;

69     nlefttoread--;

70     printf("thread %d for %s done ", fptr->f_tid, fptr->f_name);

71    }

72   }

73   Pthread_mutex_unlock(&ndone_mutex);

74  }

75  exit(0);

76 }

По возможности создаем новый поток

44-56 Эта часть кода не изменилась.

Ждем завершения выполнения потока

57-60 Мы ждем завершения выполнения потоков, отслеживая, когда значение ndone станет равно нулю. Как сказано в разделе 26.8, эта проверка должна быть проведена перед тем, как взаимное исключение будет блокировано, а переход потока в состояние ожидания осуществляется функцией pthread_cond_wait.

Обработка завершенного потока

61-73 Когда выполнение потока завершилось, мы перебираем все структуры file, отыскивая соответствующий поток, вызываем pthread_join, а затем устанавливаем новый флаг F_JOINED.

В табл. 16.1 показано, сколько времени требует выполнение этой версии веб-клиента, а также версии, использующей неблокируемую функцию connect.

Данный текст является ознакомительным фрагментом.