2009-12-16 62 views
2

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

我想要达到的目标是在第一次打开文件时截断文件,然后让几个打开的进程完成所有写操作。 所有的写操作都是系统刷新和互斥保护的,这样我就不会出现混乱的输出。

首先,进程创建文件,然后启动一系列其他进程,一次一个,然后打开文件并写入文件(主控制器有时会插入其他内容;从属进程可能或可能不要开放和写作)。

我希望尽可能不要使用已存在的更多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(); 

好了,这不工作:虽然从过程的输出是有序的预期,何师傅写或者是聚集在一起或者在错误的地方,当它存在时。

我有两个问题:给thestream的构造函数提供的标志组合是正确的吗?无论如何,我的方向是否正确?

+1

你还记录一个时间戳吗?如果是这样,你可以看到排序是否正确。也许你的日志记录是正确的,但你的主进程正在做你没想到的事情 – Toad 2009-12-16 16:42:02

+0

/我踢自己。时间戳揭示了事实:这些事件并不按照我认为的那样发生。谢谢你的提示 ! – 2009-12-16 18:36:28

回答

1

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

fstreams做得很好。

我错过了主从机之间的同步(前者假定某个特定操作是同步的,而不是)。

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

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

0

如何创建该互斥锁?
为了这个工作,这需要是一个有名的互斥体,这样两个进程实际上锁定在同一个事物上。
您可以检查您的互斥锁实际上是否正确地使用一小段代码将其锁定在一个进程中,另一个进程尝试获取它。

+0

哦,为了简洁起见,我实际上放弃了创作部分。它是一个有名的互斥体,它可以正常工作。 – 2009-12-16 16:34:24

1

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

通过使用异步I/O,你可以做得比这更好,但这会变得更棘手。

+0

我想这将是一个明智的方法,即使对于多进程设计......但我需要实现一些进程间通信,我不想这样做。 – 2009-12-16 18:35:29

0

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

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

+0

我认为std :: flush确保在返回之前完成写入操作(我的准独特用例是写入本地文件)(并且它的工作至今)。 时间戳的确向我展示了问题所在。 – 2009-12-18 15:17:39

1

我做了一个'lil日志系统,它有自己的过程,并将处理写作过程,这个想法是相当模糊的。使用日志的进程只是将它们发送到日志进程将尝试写入文件的待处理队列。这就像批处理在任何实时渲染应用程序。这样你就可以摆脱太多的打开/关闭文件操作。如果我可以,我会添加示例代码。

+0

非常简单的确,绝对是下一次我需要它的探索选项! – 2010-01-07 16:20:39

0

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