Глобальный мьютекс в Linux
Сразу: Linux не моё, так что, возможно, напишу ерунду и решение давно есть, просто я его не нагуглил...
Имеется расчетная программа, запускается во многих экземплярах, т.е. имеем не многопоточность, а многопроцессность. И все они лезут время от времени в один и тот же файл. В Windows все просто, именованный глобальный мьютекс, и если что — все дружно выстраиваются в очередь.
Теперь надо то же самое посчитать, чтоб побыстрее, на мощном многопроцессорном сервере под Ubuntu. Количество процессов возросло примерно на порядок, так что вопрос синхронизации весьма важен. После бесед с ИИ :) и копания в литературе родился такой файловый глобальный мьютекс:
class GlobalMutex {
private:
int lockFileDescriptor;
public:
GlobalMutex(const char * lockFilePath) {
lockFileDescriptor = open(lockFilePath, O_CREAT | O_RDWR, 0666);
if (lockFileDescriptor == -1) {
throw std::runtime_error("GlobalMutex: failed to open lock file");
}
}
~GlobalMutex() {
close(lockFileDescriptor);
}
void request() {
if (flock(lockFileDescriptor, LOCK_EX) == -1) {
throw std::runtime_error("GlobalMutex: failed to acquire lock");
}
}
void release() {
if (flock(lockFileDescriptor, LOCK_UN) == -1) {
throw std::runtime_error("GlobalMutex: failed to release lock");
}
}
GlobalMutex() = delete;
GlobalMutex(const GlobalMutex&) = delete;
GlobalMutex& operator = (const GlobalMutex&) = delete;
};
Не скажу, что он вообще не работает, но судя по результатам, где-то он все же ухитряется пропустить два процесса одновременно, а это категорически непозволительно, одна ночь на сервере уже пошла коту под хвост :( Блокировка файла неатомарна?
Впрочем, это вопрос хоть и интересный, но второй. А первый — как быстренько набросать глобальный мьютекс под Linux с таким вот интерфейсом (да попроще, так как, как я уже писал, я с Linux не очень дружен), чтоб саму программу не переделывать?
Ответы (1 шт):
Вот тут, через semop и через semget реализован именованный мьютекс
Сценарий примерно такой: Создаем файл - мьютекс:
fd = open(fileName.c_str(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
_semid = semget(key, 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | IPC_CREAT | IPC_EXCL);
semctl(_semid, 0, SETVAL, arg);
lock:
struct sembuf op;
op.sem_num = 0;
op.sem_op = -1;
op.sem_flg = SEM_UNDO;
int err;
do
{
err = semop(_semid, &op, 1);
}
while (err && errno == EINTR);
unlock:
struct sembuf op;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = SEM_UNDO;
semop(_semid, &op, 1);