首页 > 解决方案 > C - 多个进程写入同一个日志文件

问题描述

我有一个非常简单的 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() 系统调用是atomic,至少在 POSIX 兼容系统中是这样吗?

额外的问题:假设日志记录函数使用两个 write() 调用而不是一个。同步机制不应该再是可选的了,因为我想确保这两个调用被执行而不会被另一个进程中断。在这种情况下我应该使用的最简单的锁定对象是什么?互斥量就足够了吗?

标签: cconcurrencylockingforkmutex

解决方案


:“我必须为日志文件引入任何同步(锁定)逻辑吗?”

:是的。同时写入同一个文件会产生竞争条件和不良行为。

:“鉴于“关键部分”是单个 write() 调用:由于操作系统调度,同一文件描述符上的多个 write() 调用是否可以“混合”?这是真正的风险吗?

:是的,你的例子可能会发生。

要改进您的代码,请打开日志文件一次,并跟踪文件描述符。在里面使用互斥锁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");

推荐阅读