Является ли использование fcntl F_SETLKW в STDOUT_FILENO законным? - PullRequest
2 голосов
/ 23 марта 2019

У меня есть несколько процессов, порожденных через форк из основной программы, что означает, что они выводят на один и тот же стандартный вывод (который я хочу). Однако мне нужно как-то предотвратить чередование вывода. Я уже использую блокировки fcntl для синхронизации доступа к файлу журнала, поэтому я хотел использовать его также для stdout.

Однако в этом сообщении в блоге утверждается, что блокировки fcntl равны associated with an [i-node, pid] pair. У stdout есть инод? Я решил просто попробовать

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void do_log(const char *msg) {
    printf("%5ld: %s\n", getpid(), msg);
}

void try_lock(void) {
    do_log("Trying to lock stdout...");

    struct flock fl = {
        .l_type = F_WRLCK,
        .l_whence = SEEK_SET,
        .l_start = 0,
        .l_len = 0,
    };
    if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
        perror("fcntl - lock");
        exit(1);
    }

    do_log("Stdout locked");
    sleep(2);
    do_log("Trying to unlock stdout...");

    fl.l_type = F_UNLCK;
    if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1) {
        perror("fcntl - unlock");
        exit(1);
    }

    do_log("Stdout unlocked");
}

int main(void) {
    if (fork()) {
        try_lock();
    } else {
        try_lock();
    }
    wait(NULL);
    return 0;
}

, который, кажется, работает

17156: Trying to lock stdout...
17155: Trying to lock stdout...
17155: Stdout locked
17155: Trying to unlock stdout...
17155: Stdout unlocked
17156: Stdout locked
17156: Trying to unlock stdout...
17156: Stdout unlocked

но в man-странице для fcntl я заметил If fildes refers to a typed memory object, the result of the fcntl() function is unspecified., и я понятия не имею, что это значит.

Итак, я думаю, у меня есть два вопроса:

  1. Гарантируется ли использование блокировки fcntl на stdout, как это?
  2. Если ответ на вопрос 1. Да, является ли сообщение в блоге неправильным о [i-node, pid] или в stdout действительно есть i-узел?

1 Ответ

1 голос
/ 23 марта 2019

Номер индекса (вместе с номером устройства) является чисто уникальным идентификатором файла.При современном использовании этого термина он не имеет ничего общего со структурами файловых систем на диске.Все файлы (и файловые дескрипторы ссылаются на экземпляры открытых файлов) имеют номер инода, и выполнение fcntl как минимум «имеет смысл» для них.Однако для POSIX:

Блокировка записи должна поддерживаться для обычных файлов и может поддерживаться для других файлов.

Возможно, что существуют типы файлов, для которыхLinux не поддерживает блокировки;Я не уверен.

Обратите также внимание, что блокировка является чисто консультативной - она ​​не действует, если процессы, выполняющие запись, не пытаются захватить блокировку перед выполнением их доступа.

Может иметь больше смысла, особенно если вы используете fork без exec для блокировки через разделяемую память.Перед разветвлением mmap a MAP_ANON|MAP_SHARED регион и настройте в нем мьютекс с общим процессом.Вы можете сделать это надежным мьютексом, если какой-либо процесс может неожиданно умереть.Это гарантированно сработает, и должно быть быстрее, так как это чисто пользовательская операция, за исключением конфликта блокировок.

...