C - несколько процессов записи в один и тот же файл журнала - PullRequest
1 голос
/ 05 марта 2019

У меня очень простой C-сервер: основной процесс - прослушивание определенного порта. Когда приходит новый запрос, вызывается fork (): дочерний процесс входит в функцию под названием dosomething (), возвращает ответ клиенту, регистрирует все в текстовом файле и затем умирает. Это упрощенный вид:

void dosomething(int socketFd)
{
    /* ... */
    //Reads the request and sends a response
    writetolog("[INFO] Request accepted. Sent response message -> ", buffer);
    /* ... */
}

Это функция регистрации:

void writetolog(char* logString1, char* logString2)
{
    /* ... */
    //Prepends date and time, and formats everything nicely into a single char[]
    if ((logFd = open("SocketServer.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) >= 0) {
        write(logFd, logBuffer, strlen(logBuffer));
        close(logFd);
    }
}

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

Учитывая, что "критическая секция" - это тот единственный вызов write (): Может ли несколько вызовов write () для одного и того же файлового дескриптора быть «смешанными» из-за планирования ОС? Это реальный риск? Например:

Process1 wants to write "ABC"
Process2 wants to write "123"
Result: "AB1C23"

Я попытался отправить тысячи запросов от трех разных клиентов в одно и то же время. Файл журнала записывался правильно каждый раз, без «смешения». Можно ли сделать вывод, что системный вызов write () является атомарным , по крайней мере, в POSIX-совместимых системах?

Бонусный вопрос : допустим, что функция регистрации использует два вызова write () вместо одного. Механизм синхронизации больше не должен быть необязательным, потому что я хочу убедиться, что два вызова выполняются без прерывания другим процессом. Какой простейший объект блокировки я должен использовать в этом случае? Mutex будет достаточно?

1 Ответ

0 голосов
/ 05 марта 2019

Q : "Нужно ли вводить какую-либо логику синхронизации (блокировки) для файла журнала?"

A : Да.Одновременная запись в один и тот же файл может привести к состояниям состязания и нежелательному поведению.

Q : «Учитывая, что« критическая секция »- это единственный вызов write (): можно несколько вызовов write ()»в одном и том же файловом дескрипторе быть "смешанным" из-за планирования ОС? Это реальный риск? "

A : Да, и ваш пример может случиться.

Чтобы улучшить код, откройте файл журнала один раз и следите за дескриптором файла.Используйте блокировку мьютекса внутри writetolog.

Я написал новую версию writetolog с поддержкой нескольких параметров (например, printf):

Проверка Совместное использование переменной условия и взаимного исключения между процессами: нужно ли блокировать мьютекс раньше? для инициализации pthread_mutex_t _mutex_log_file

#MAX_LEN_LOG_ENTRY 1024

// _log_fd is a file descriptor previously opened

void writetolog (char *fmt, ...)
{
    va_list ap;
    char   msg[MAX_LEN_LOG_ENTRY];

    va_start(ap, fmt);
    vsnprintf(msg, MAX_LEN_LOG_ENTRY - 1, fmt, ap);
    va_end(ap);

    pthread_mutex_lock (&_mutex_log_file);

    fprintf (_log_fd, "[ LOG ] %s\n", msg);
    fflush(_log_fd);

    pthread_mutex_unlock (&_mutex_log_file);
}

Пример вызова writetolog:

writetolog("Testing log function: %s %s %s", "hello", "world", "good");
...