37 shared.buff[i % NBUFF] = i; /* помещение i в циклический буфер */
38 Sem_post(&shared.mutex);
39 Sem_post(&shared.nstored); /* поместили еще один элемент */
40 }
41 return(NULL);
42 }
43 void *
44 consume(void *arg)
45 {
46 int i;
47 for (i = 0; i < nitems; i++) {
48 Sem_wait(&shared.nstored); /* ожидаем появления хотя бы одного готового для обработки элемента */
49 Sem_wait(&shared.mutex);
50 if (shared.buff[i % NBUFF] != i)
51 printf("buff[*d] = *d\n", i, shared.buff[i % NBUFF]);
52 Sem_post(&shared.mutex);
53 Sem_post(&shared.nempty); /* еще одно пустое поле */
54 }
55 return(NULL);
56 }
Выделение семафоров
6 Мы объявляем три семафора типа sem_t, и теперь это сами семафоры, а не указатели на них.
Вызов sem_init
16-27 Мы вызываем sem_init вместо sem_open* а затем sem_destroy вместо sem_unlink. Вызывать sem_destroy на самом деле не требуется, поскольку программа все равно завершается.
Остальные изменения обеспечивают передачу указателей на три семафора при вызовах sem_wait и sem_post.
10.9. Несколько производителей, один потребитель
Решение в разделе 10.6 относится к классической задаче с одним производителем и одним потребителем. Новая, интересная модификация программы позволит нескольким производителям работать с одним потребителем. Начнем с решения из листинга 10.11, в котором использовались размещаемые в памяти семафоры. В листинге 10.12 приведены объявления глобальных переменных и функция main.
Листинг 10.12. Функция main задачи с несколькими производителями
//pxsem/prodcons3.c
1 #include "unpipc.h"
2 #define NBUFF 10
3 #define MAXNTHREADS 100
4 int nitems, nproducers; /* только для чтения производителем и потребителем */
5 struct { /*
общие данные */
6 int buff[NBUFF];
7 int nput;
8 int nputval;
9 sem_t mutex, nempty, nstored; /* семафоры, а не указатели */
32 /* ожидание завершения всех производителей и потребителя */
33 for (i = 0; i < nproducers; i++) {
34 Pthread_join(tid_produce[i], NULL);
35 printf("count[%d] = %d\n", i, count[i]);
36 }
37 Pthread_join(tid_consume, NULL);
38 Sem_destroy(&shared.mutex);
39 Sem_destroy(&shared.nempty);
40 Sem_destroy(&shared.nstored);
41 exit(0);
42 }
Глобальные переменные
4 Глобальная переменная nitems хранит число элементов, которые должны быть совместно произведены. Переменная nproducers хранит число потоков-производителей. Оба эти значения устанавливаются с помощью аргументов командной строки.
Общая структура
5-10 В структуру shared добавляются два новых элемента: nput, обозначающий индекс следующего элемента, куда должен быть помещен объект (по модулю BUFF), и nputval —следующее значение, которое будет помещено в буфер. Эти две переменные взяты из нашего решения в листингах 7.1 и 7.2. Они нужны для синхронизации нескольких потоков-производителей.
Новые аргументы командной строки
17-20 Два новых аргумента командной строки указывают полное количество элементов, которые должны быть помещены в буфер, и количество потоков-производителей.