15   return(-1);

16  return(0);

17 }

<p>Функция sem_wait</p>

Следующая функция приведена в листинге 10.42; она называется sem_wait и ожидает изменения значения семафора с нулевого на ненулевое, после чего уменьшает значение семафора на 1.

11-16 Мы вызываем semop с операцией, уменьшающей значение семафора на 1.

Листинг 10.42. Функция sem_wait

//my_pxsem_svsem/sem_wait.c

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_wait(mysem_t *sem)

5  {

6   struct sembuf op;

7   if (sem-sem_magic != SEM_MAGIC) {

8    errno = EINVAL;

9    return(-1);

10  }

11  op.sem_num = 0;

12  op.sem_op = –1;

13  op.sem_flg = 0;

14  if (semop(sem-sem_semid, op, 1) 0)

15   return(-1);

16  return(0);

17 }

<p>Функция sem_trywait</p>

В листинге 10.43 приведен текст нашей функции sem_trywait, которая представляет собой неблокируемую версию sem_wait.

13 Единственное отличие от функции sem_wait из листинга 10.42 заключается в том, что флагу sem_flg присваивается значение IPC_NOWAIT. Если операция не может быть завершена без блокирования вызвавшего потока, функция semop возвращает ошибку EAGAIN, а это именно тот код, который должен быть возвращен sem_trywait, если операция не может быть завершена без блокирования потока.

Листинг 10.43. Функция sem_trywait

//my_pxsem_svsem/sem_trywait.c

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_trywait(mysem_t *sem)

5  {

6   struct sembuf op;

7   if (sem-sem_magic != SEM_MAGIC) {

8    errno = EINVAL;

9    return(-1);

10  }

11  op.sem_num = 0;

12  op.sem_op = –1;

13  op.sem_flg = IPC_NOWAIT;

14  if (semop(sem-sem_semid, op, 1) 0)

15   return(-1);

16  return(0);

17 }

<p>Функция sem_getvalue</p>

Последняя функция приведена в листинге 10.44. Это функция sem_getvalue, возвращающая текущее значение семафора.

11-14 Текущее значение семафора получается отправкой команды GETVAL функции semctl.

Листинг 10.44. Функция sem_getvalue

//my_pxsem_svsem/sem_getvalue.с

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_getvalue(mysem_t *sem, int *pvalue)

5  {

6   int val;

7   if (sem-sem_magic != SEM_MAGIC) {

8    errno = EINVAL;

9    return(-1);

10  }

11  if ((val = semctl(sem-sem_semid, 0, GETVAL)) 0)

12   return(-1);

13  *pvalue = val;

14  return(0);

15 }

<p>10.17. Резюме</p>

Семафоры Posix представляют собой семафоры-счетчики, для которых определены три основные операции:

1. Создание семафора.

2. Ожидание изменения значения семафора на ненулевое и последующее уменьшение значения.

3. Увеличение значения семафора на 1 и возобновление выполнения всех процессов, ожидающих его изменения.

Семафоры Posix могут быть именованными или неименованными (размещаемыми в памяти). Именованные семафоры всегда могут использоваться отдельными процессами, тогда как размещаемые в памяти должны для этого изначально планироваться как разделяемые между процессами. Эти типы семафоров также отличаются друг от друга по живучести: именованные семафоры обладают по меньшей мере живучестью ядра, тогда как размещаемые в памяти обладают живучестью процесса.

Задача производителей и потребителей является классическим примером для иллюстрации использования семафоров. В этой главе первое решение состояло из одного потока-производителя и одного потока-потребителя; второе решение имело нескольких производителей и одного потребителя, а последнее решение допускало одновременную работу и нескольких потребителей. Затем мы показали, что классическая задача двойной буферизации является частным случаем задачи производителей и потребителей с одним производителем и одним потребителем.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже