同时写入文件

时间:2009-12-16 16:10:33

标签: c++ windows fstream

我有这个工具,其中一个类似日志的文件被多个进程写入。

我想要实现的是在首次打开文件时截断文件,然后通过打开它的几个进程完成所有写入操作。 所有写入都被系统地刷新并受到互斥保护,这样我就不会得到混乱的输出。

首先,进程创建文件,然后一次启动一系列其他进程,然后打开文件并写入文件(主服务器有时会插入其他内容;从属进程可能会也可能不会开放并写一些东西)。

我希望尽可能不使用已经存在的更多的IPC(我现在正在做的就是写一个popen创建的管道)。我无法访问CRT和Win32 API之外的其他库,我也不想开始编写序列化代码。

以下是一些显示我已离开的地方的代码:

// open the file. Truncate it if we're the 'master', append to it if we're a 'slave'
std::ofstream blah(filename, ios::out | (isClient ? ios:app : 0));

// do stuff...

// write stuff
myMutex.acquire();
blah << "stuff to write" << std::flush;
myMutex.release();

嗯,这不起作用:虽然从属进程的输出按预期排序,但是当它存在时,主要写入的内容要么聚集在一起,要么位于错误的位置。

我有两个问题:给ofstream的构造函数赋予正确的标志组合吗?我还是走对了路吗?

6 个答案:

答案 0 :(得分:1)

如果您要从多个线程向日志中写入大量数据,则需要重新考虑设计,因为所有线程都会阻止尝试获取互斥锁,并且通常您不希望线程被阻止做工作,所以他们可以记录。在这种情况下,您需要编写工作线程以将日志条目记录到队列中(这只需要在内存中移动内容),并且有一个专用线程将条目从队列中拉出并将它们写入输出。这样你的工作线程就会被阻塞的时间尽可能短。

使用异步I / O可以做得更好,但这有点棘手。

答案 1 :(得分:1)

正如reinier所建议的那样,问题不在于我使用文件的方式,而在于程序的行为方式。

fstreams做得很好。

我错过的是主设备和从设备之间的同步(前者假设特定操作是同步的,而不是)。

编辑:哦,打开的标志仍然存在问题。使用ios :: out打开文件的进程没有根据需要移动文件指针(删除其他进程写入的文本),并且在写入cout时使用seekp()完全搞砸了输出,因为代码的另一部分使用了cerr。

我的最终解决方案是保留互斥锁和刷新,并且对于主进程,以ios :: out模式打开文件(创建或截断文件),关闭它并使用ios :: app重新打开它

答案 2 :(得分:1)

我创建了一个'lil日志系统,它有自己的进程并且将处理写入过程,这个想法非常简短。使用日志的过程只是将它们发送到挂起队列,日志进程将尝试写入该文件。这就像在任何实时渲染应用程序中进行批处理一样。这样你就可以摆脱过多的打开/关闭文件操作。如果我可以添加示例代码。

答案 3 :(得分:0)

如何创建该互斥锁?
为了实现这一点,这需要一个命名的互斥锁,以便两个进程实际上锁定同一个东西 您可以使用一小段代码检查您的互斥锁是否正常工作,该代码将其锁定在一个进程中,另一个进程尝试获取它。

答案 4 :(得分:0)

我建议阻塞,以便在释放互斥锁之前将文本完全写入文件。我有一些实例,其中一个任务的文本被来自更高优先级的线程的文本中断;看起来不太漂亮。

此外,将格式设置为逗号分隔格式,或者可以轻松加载到电子表格中的某种格式。包括线程ID和时间戳。文本行的隔行扫描显示了线程如何交互。 ID参数允许您按线程排序。时间戳可用于显示顺序访问以及持续时间。以电子表格友好格式编写将允许您使用外部工具分析日志文件,而无需编写任何转换实用程序。这对我帮助很大。

答案 5 :(得分:0)

一种选择是使用ACE :: logging。它具有并发日志记录的高效实现。