Я делаю то же самое в некотором коде, который у меня есть, и он выглядит очень похоже - частично.Идея действительно довольно проста.Размер пространства, выделенного для мьютекса, составляет ровно sizeof(pthread_mutex_t)
.Вы создаете общий файл, mmap
его и инициализируете мьютекс в одном процессе, тогда другие могут просто mmap
файл и установить на него указатель pthread_mutex_t *
.
Одна вещь, которую я не понимаюэто struct GenQ
часть.Ключевые слова volatile
намекают на то, что эта структура уже находится в общей памяти.Однако, если в общей памяти , указатель мьютекса, который вы там храните , не будет действительным вне процесса, который его создал.Сам мьютекс может находиться в общей памяти, и другие процессы могут иметь указатель на мьютекс, но точное местоположение области общей памяти в их виртуальном адресном пространстве может отличаться, следовательно, их значение указателя также будет отличаться (и, следовательно, указатель должен быть закрытым для процесса).
Итак, если структура GenQ
уже уже в общей памяти, почему бы просто не объявить pthread_mutex_t
( not указатель - пространство для фактического мьютекса) в структуре GenQ
, а затем выполните ту же инициализацию из вашего основного процесса, что и в приведенном выше коде.Тогда вам не нужен отдельный файл общей памяти для мьютекса;он будет находиться в той же области разделяемой памяти, что и другая информация об очереди.
Также рассмотрите возможность добавления атрибута PTHREAD_MUTEX_ROBUST
(с pthread_mutexattr_setrobust
) в мьютекс, чтобы вы могли восстановить его в случаегде происходит сбой одного из процессов при удержании блокировки.
Этот код выглядит примерно так:
int err = pthread_mutex_lock(mutex_ptr);
if (err) {
if (err == EOWNERDEAD) {
WARN("Mutex owner died while holding -- recovering");
err = pthread_mutex_consistent(mutex_ptr);
if (err)
FATAL("Huh?");
} else {
FATAL("Wha?");
}
}
Наконец, я бы сказал, что вы используете volatile
.Это не является ни необходимым, ни достаточным.Если вы обращаетесь к разделяемым переменным, когда вы держите мьютекс, квалификатор volatile
не нужен.Если вы не удерживаете мьютекс, то volatile
сам по себе недостаточно для обеспечения правильной синхронизации - вам все равно нужно будет использовать какой-то атомный инкремент / декремент или атомарный метод сравнения и замены.