• Некоторые реализации не поддерживают семафоры, разделяемые между процессами. Если аргументу pshared в такой системе передать ненулевое значение, то вызов sem_init() вернет ошибку. До версии 2.6 и появления NPTL-потоков ядро Linux не поддерживало анонимные семафоры этого типа (в старой реализации многопоточности, LinuxThreads, передача аргументу pshared ненулевого значения приводила к ошибке ENOSYS).
• Если реализация поддерживает разделение семафоров между процессами и потоками, то выбор типа разделения может оказаться необходимым, так как для поддержки того или иного режима системе нужно выполнить определенные действия. Предоставление этой информации может также позволить системе оптимизировать работу с учетом типа разделения.
NPTL-реализация функции sem_init() игнорирует аргумент pshared, поскольку ни один из типов разделения не требует специальных действий. Тем не менее приложения, которые пишутся с учетом разных платформ или рассчитаны на будущие изменения, должны указывать для аргумента pshared подходящее значение.
Стандарт SUSv3 отмечает: в случае неудачного завершения функция sem_init() возвращает -1, однако в нем ничего не сказано относительно значения, которое возвращается при успешном выполнении. Тем не менее в руководствах к большинству современных UNIX-систем говорится о том, что в случае успеха возвращается 0. (Одним из заметных исключением является Solaris, где описание возвращаемого значения похоже на представленное в стандарте SUSv3; однако, судя по исходному коду OpenSolaris, функция sem_init() при успешном выполнении тоже возвращает 0.) Стандарт SUSv4 исправляет ситуацию, явно определяя значение 0 на случай успешного выполнения sem_init().
У анонимных семафоров нет параметров, описывающих права доступа (то есть функция sem_init() не имеет аргумента, аналогичного mode в вызове sem_open()). Доступ к этим семафорам регулируется на основе привилегий, выданных процессу для использования соответствующего участка памяти.
Стандарт SUSv3 гласит: инициализация уже инициализированного анонимного семафора приводит к неопределенным последствиям. Иными словами, мы должны проектировать свои приложения так, чтобы только один процесс вызывал функцию sem_init() для инициализации семафора.
Как и в случае с именованными семафорами, стандарт SUSv3 говорит о том, что в случае работы с
В подразделе 30.1.2 была представлена программа (см. листинг 30.2), которая использует мьютексы для защиты критического участка кода, где два потока обращались к одной и той же глобальной переменной. Программа, показанная в листинге 49.6, решает ту же проблему, но с помощью анонимного семафора, разделяемого между потоками.
Листинг 49.6. Применение анонимного POSIX-семафора для регулирования доступа к глобальной переменной
psem/thread_incr_psem.c
#include
#include
#include "tlpi_hdr.h"
static int glob = 0;
static sem_t sem;
static void * /* Выполняем 'arg' итераций, инкрементируя 'glob' */
threadFunc(void *arg)
{
int loops = *((int *) arg);
int loc, j;
for (j = 0; j < loops; j++) {
if (sem_wait(&sem) == -1)
errExit("sem_wait");
loc = glob;
loc++;
glob = loc;
if (sem_post(&sem) == -1)
errExit("sem_post");
}
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t t1, t2;
int loops, s;
loops = (argc > 1)? getInt(argv[1], GN_GT_0, "num-loops"): 10000000;
/* Инициализируем семафор, разделяемый между потоками, с помощью значения 1 */
if (sem_init(&sem, 0, 1) == -1)
errExit("sem_init");
/* Создаем два потока, которые инкрементируют 'glob' */
s = pthread_create(&t1, NULL, threadFunc, &loops);
if (s!= 0)
errExitEN(s, "pthread_create");
s = pthread_create(&t2, NULL, threadFunc, &loops);
if (s!= 0)
errExitEN(s, "pthread_create");
/* Ждем завершения потоков */
s = pthread_join(t1, NULL);
if (s!= 0)
errExitEN(s, "pthread_join");
s = pthread_join(t2, NULL);
if (s!= 0)
errExitEN(s, "pthread_join");
printf("glob = %d\n", glob);
exit(EXIT_SUCCESS);
}
psem/thread_incr_psem.c
49.4.2. Уничтожение анонимного семафора
Функция sem_destroy() уничтожает анонимный семафор sem, инициализированный ранее с помощью вызова sem_init(). Эта процедура является безопасной только в том случае, если доступа к семафору не ожидает ни один поток или процесс.
#include
int sem_destroy(sem_t *
Возвращает 0 при успешном завершении или -1 при ошибке
После уничтожения участка памяти с анонимным семафором его можно снова инициализировать, используя функцию sem_init().