Глобальный мьютекс в 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 шт):

Автор решения: Rikitikitavi

Вот тут, через 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);
→ Ссылка