Читаем UNIX Network Programming. Volume 2 Second Edition. Interprocess Communications полностью

28  waitop.sem_op = –1;

29  waitop.sem_flg = 0;

30  /* создание всех потоков */

31  Set_concurrency(nthreads);

32  for (i = 0; i nthreads; i++) {

33   Pthread_create(tid[i], NULL, incr, NULL);

34  }

35  /* запуск таймера и разблокирование семафора */

36  Start_time;

37  Semop(shared.semid, postop, 1); /* up by 1 */

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

39  for (i = 0; i nthreads; i++) {

40   Pthread_join(tid[i], NULL);

41  }

42  printf("microseconds: %.0f usec\n", Stop_time);

43  if (shared.counter != nloop * nthreads)

44   printf("error: counter = %ld\n", shared, counter);

45  Semctl(shared.semid, 0, IPC_RMID);

46  exit(0);

47 }

Листинг А.28. Увеличение общего счетчика с использованием семафоров System V

//bench/incr_svsem1.c

48 void *

49 incr(void *arg)

50 {

51  int i;

52  for (i = 0; i nloop; i++) {

53   Semop(shared.semid, waitop, 1);

54   shared.counter++;

55   Semop(shared.semid, postop, 1);

56  }

57  return(NULL);

58 }

20-23 Создается семафор с одним элементом, значение которого инициализируется нулем.

24-29 Инициализируются две структуры semop: одна для увеличения семафора, а другая для ожидания его изменения. Обратите внимание, что поле sem_flg в обеих структурах имеет значение 0: флаг SEM_UNDO не установлен.

Семафоры System V с флагом SEM_UNDO

Единственное отличие от пpoгрaммы из листинга А.27 заключается в том, что поле sem_flg структур semop устанавливается равным SEM_UNDO, а не 0. Мы не приводим в книге новый листинг с этим небольшим изменением.

Блокировка записей fcntl

Последняя пpoгрaммa использует fcntl для синхронизации. Функция main приведена в листинге А.30. Эта программа будет выполняться успешно только в том случае, если количество потоков равно 1, поскольку блокировка fcntl предназначена для использования между процессами, а не между потоками одного процесса. При указании нескольких потоков каждый из них всегда имеет возможность получить блокировку (то есть вызовы writew_lock не приводят к остановке потока, потому что процесс уже является владельцем блокировки), и конечное значение счетчика оказывается неправильным.

Функция incr, использующая блокировку записей, приведена в листинге А.29.

Листинг А.29. Увеличение общего счетчика с использованием блокировки записей fcntl

//bench/incr_fcntl1.e

44 void *

45 incr(void *arg)

46 {

47  int i;

48  for (i = 0; i nloop; i++) {

49   Writew_lock(shared.fd, 0, SEEK_SET, 0);

50   shared.counter++;

51   Un_lock(shared.fd, 0, SEEK_SET, 0);

52  }

53 return(NULL);

54 }

Листинг А.30. Функция main для измерения производительности блокировки fcntl

//bench/incr_fcntl1.e

4  #include "unpipc.h"

5  #define MAXNTHREADS 100


6  int nloop;

7  struct {

8   int fd;

9   long counter;

10 } shared;

11 void *incr(void *);


12 int

13 main(int argc, char **argv)

14 {

15  int i, nthreads;

16  char *pathname;

17  pthread_t tid[MAXNTHREADS];

18  if (argc != 4)

19   err_quit("usage: incr_fcntll pathname #loops #threads");

20  pathname = argv[1];

21  nloop = atoi(argv[2]);

22  nthreads = min(atoi(argv[3]), MAXNTHREADS);

23  /* создание файла и получение блокировки на запись */

24  shared.fd = Open(pathname, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);

25  Writew_lock(shared.fd, 0, SEEK_SET, 0);

26  /* создание всех потоков */

27  Set_concurrency(nthreads);

28  for (i = 0; i nthreads; i++) {

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