C - 多个进程写入同一个日志文件
C - Multiple processes writing to the same log file
我有一个非常简单的 C 套接字服务器:主进程侦听特定端口。当新请求到达时,将调用 fork():子进程进入一个名为 dosomething() 的函数,returns 对客户端的响应,将所有内容记录在文本文件中,然后结束。这是一个简化的视图:
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);
}
}
现在,我的问题是:既然这个服务器(理论上)能够同时处理多个请求(因此,多个进程可能想要在日志中写一些东西),我是否必须引入任何同步(锁定)逻辑日志文件?
鉴于 "critical section" 是单个 write() 调用:
由于 OS 调度,同一文件描述符上的多个 write() 调用是否可以 "mixed"?这是真正的风险吗?
例如:
Process1 wants to write "ABC"
Process2 wants to write "123"
Result: "AB1C23"
我尝试同时从三个不同的客户端发送数千个请求window。日志文件每次都正确写入,根本没有 "mixing"。我可以得出结论,write() 系统调用是 atomic,至少在 POSIX 兼容系统中是这样吗?
奖金问题:假设日志记录函数使用两个 write() 调用而不是一个。同步机制不应该再是可选的,因为我想确保这两个调用在不被另一个进程中断的情况下执行。在这种情况下我应该使用的最简单的锁定对象是什么?互斥就够了吗?
Q: "Do I have to introduce any synchronization (locking) logic for the log file?"
A:是的。同时写入同一个文件会产生竞争条件和不良行为。
Q: "Given that the "临界区”是单个 write() 调用:可以对同一个文件描述符进行多个 write() 调用 "mixed"因为 OS 日程安排?这真的有风险吗?”
A:是的,你的例子可能会发生。
要改进您的代码,请打开日志文件一次,并跟踪文件描述符。在 writetolog
.
中使用互斥锁
我写了一个新版本 writetolog
支持多参数(比如 printf):
检查 Share condition variable & mutex between processes: does mutex have to locked before? 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");
我有一个非常简单的 C 套接字服务器:主进程侦听特定端口。当新请求到达时,将调用 fork():子进程进入一个名为 dosomething() 的函数,returns 对客户端的响应,将所有内容记录在文本文件中,然后结束。这是一个简化的视图:
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);
}
}
现在,我的问题是:既然这个服务器(理论上)能够同时处理多个请求(因此,多个进程可能想要在日志中写一些东西),我是否必须引入任何同步(锁定)逻辑日志文件?
鉴于 "critical section" 是单个 write() 调用: 由于 OS 调度,同一文件描述符上的多个 write() 调用是否可以 "mixed"?这是真正的风险吗? 例如:
Process1 wants to write "ABC"
Process2 wants to write "123"
Result: "AB1C23"
我尝试同时从三个不同的客户端发送数千个请求window。日志文件每次都正确写入,根本没有 "mixing"。我可以得出结论,write() 系统调用是 atomic,至少在 POSIX 兼容系统中是这样吗?
奖金问题:假设日志记录函数使用两个 write() 调用而不是一个。同步机制不应该再是可选的,因为我想确保这两个调用在不被另一个进程中断的情况下执行。在这种情况下我应该使用的最简单的锁定对象是什么?互斥就够了吗?
Q: "Do I have to introduce any synchronization (locking) logic for the log file?"
A:是的。同时写入同一个文件会产生竞争条件和不良行为。
Q: "Given that the "临界区”是单个 write() 调用:可以对同一个文件描述符进行多个 write() 调用 "mixed"因为 OS 日程安排?这真的有风险吗?”
A:是的,你的例子可能会发生。
要改进您的代码,请打开日志文件一次,并跟踪文件描述符。在 writetolog
.
我写了一个新版本 writetolog
支持多参数(比如 printf):
检查 Share condition variable & mutex between processes: does mutex have to locked before? 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");