进程之间的并发文件写入

时间:2016-02-24 07:37:07

标签: c++ .net synchronization c++-cli mutex

我需要将日志数据写入来自不同进程的单个文件中。

我正在使用Windows Mutex,它需要Common Language Runtime支持。

Mutex^ m = gcnew Mutex( false,"MyMutex" );
m->WaitOne();
//... File Open and Write ..
m->ReleaseMutex()

我是否真的需要从C ++更改为C ++ / CLI进行同步?

如果不使用原子就可以了。但我需要知道,与本地互斥锁相比,使用此互斥锁是否会降低性能。

2 个答案:

答案 0 :(得分:6)

为获取Mutex类而向您的C ++应用程序添加CLR支持是过度的。您可以使用多个选项在两个应用程序之间同步文件访问。

选项1:Mutex

如果您需要从多个进程编写文件,使用互斥锁是一种很好的方法。使用Win32 API中的mutex functions。 (无论如何,.Net Mutex类只是这些函数的包装。)

HANDLE mutex = CreateMutex(NULL, false, "MyMutex");

DWORD waitResult = WaitForSingleObject(mutex, INFINITE);
if (waitResult == WAIT_OBJECT_0)
{
    // TODO: Write the file
    WriteFile(...);

    ReleaseMutex(mutex);
}

正如另一个答案所指出的那样,您需要使用共享打开文件,这样您的两个应用程序都可以立即打开它。但是,这本身可能还不够:如果两个应用程序都试图写入文件的同一区域,那么您仍然需要确保一次只能写入一个应用程序。想象一下,如果两个应用程序都查看文件的大小,那么它们都会尝试同时写入该字节偏移量:尽管两者都试图只追加到文件的末尾,但它们最终会互相破坏。

选项2:仅作为附加打开

如果您纯粹写到文件的末尾,并且从未尝试读取任何内容或在文件的最末端以外的任何地方写入,那么您可以使用一种特殊模式你不使用互斥锁。如果您打开文件时dwDesiredAccess设置为FILE_APPEND_DATA | SYNCHRONIZE 而没有其他(不包括FILE_WRITE_DATA),那么操作系统将负责制作确保最后写入文件的所有数据,以及写入数据的两个应用程序不会相互覆盖。 MSDN上记录了此行为:

  

如果仅设置了FILE_APPEND_DATA和SYNCHRONIZE标志,则调用者只能写入文件的末尾,并且忽略有关写入文件的任何偏移信息。但是,对于此类写入操作,文件将根据需要自动扩展。

选项3:LockFile

您可以采用的另一种方法是使用LockFile方法。使用LockFile(或LockFileEx),您可以让两个应用程序打开文件,并让每个应用程序锁定要写入的文件部分。这为您提供了比互斥锁更多的粒度,允许同时发生非重叠写入。 (在整个文件上使用LockFile将为您提供与互斥锁相同的基本效果,还有一个额外的好处,即它会阻止其他应用程序在您执行此操作时写入文件。)'如何在Raymond Chen's blog上使用LockFile的一个很好的例子。

答案 1 :(得分:1)

实际上你根本不需要使用单独的互斥锁,你可以只使用文件本身。当使用CreateFile API调用打开文件时(请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396),该调用将使用一个名为dwShareMode的参数,该参数指定其他进程允许的并发访问。值为0将阻止其他进程完全打开文件。

几乎所有用于打开文件映射到CreateFile的API都是如此,因此当您打开文件进行写入时,clr可能正在为您做正确的事。

在C运行时中还有_fsopen,它允许您使用共享标志打开文件。

我建议您测试从C#打开文件时的默认共享模式。如果默认情况下不会阻止同时打开写入,请使用C中的_fsopen(或者可能有适当的C#函数)。