24 postop.sem_num = 0; /* инициализация двух структур semop */
25 postop.sem_op = 1;
26 postop.sem_flg = 0;
27 waitop.sem_num = 0;
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 }
//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 не установлен.
Единственное отличие от пpoгрaммы из листинга А.27 заключается в том, что поле sem_flg структур semop устанавливается равным SEM_UNDO, а не 0. Мы не приводим в книге новый листинг с этим небольшим изменением.
Блокировка записей fcntl
Последняя пpoгрaммa использует fcntl для синхронизации. Функция main приведена в листинге А.30. Эта программа будет выполняться успешно только в том случае, если количество потоков равно 1, поскольку блокировка fcntl предназначена для использования между процессами, а не между потоками одного процесса. При указании нескольких потоков каждый из них всегда имеет возможность получить блокировку (то есть вызовы writew_lock не приводят к остановке потока, потому что процесс уже является владельцем блокировки), и конечное значение счетчика оказывается неправильным.
Функция incr, использующая блокировку записей, приведена в листинге А.29.
//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 }
//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
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);