我有一个非常简单的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"
我尝试在同一时间窗口中发送来自三个不同客户端的数千个请求。日志文件每次都正确写入,完全没有“混合”。我是否可以得出结论,至少在兼容POSIX的系统中,write()系统调用是 atomic ?
奖励问题:假设日志记录函数使用两个write()调用而不是一个。同步机制不再是可选的,因为我要确保两个调用都被执行而不会被另一个进程中断。在这种情况下,最简单的锁定对象是什么?互斥体就足够了吗?
答案 0 :(得分:0)
问:“我必须为日志文件引入任何同步(锁定)逻辑吗?”
A :是。同时写入同一文件会产生竞争状况和不良行为。
Q :“鉴于“关键部分”是单个write()调用:由于操作系统的调度,是否可以对同一文件描述符上的多个write()调用进行“混合”?真的有风险吗?”
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");