【发布时间】:2019-07-27 02:14:42
【问题描述】:
我有一个非常简单的 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() 调用而不是一个。同步机制不应该再是可选的了,因为我想确保执行这两个调用而不会被另一个进程中断。在这种情况下我应该使用的最简单的锁定对象是什么?互斥就够了吗?
【问题讨论】:
-
write系统调用不保证写入所有请求的字节。返回值告诉您它实际 写入了多少字节(最多为您指定的数字)。我不知道它可能会变小的所有条件,但如果输出设备空间不足,就会发生这种情况。这并不能真正回答您的问题,但值得了解。 -
我的期望(可能完全合理,也可能不完全合理)是,只要每个进程进行一次写入调用以添加消息,交错就不应该有问题。
O_APPEND标志很重要。您可能要考虑是否最好打开文件一次(在分叉之前)然后让孩子使用相同的打开文件描述(但每个都有自己的打开文件描述符 - 如果需要,请重新阅读read()规范刷新您对差异的记忆)。
标签: c concurrency locking fork mutex