进程之间的并发文件写入

Concurrent File write between processes

本文关键字:文件 并发 之间 进程      更新时间:2023-10-16

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

我正在使用Windows Mutex,它需要公共语言运行时支持。

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

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

如果不使用原子也没关系。但是我需要知道与本地互斥锁相比,使用此互斥体是否会降低性能。

仅仅为了获得互斥类而向C++应用程序添加 CLR 支持是矫枉过正的。有几个选项可用于在两个应用程序之间同步文件访问。

选项 1:互斥

如果需要从多个进程写入文件,使用互斥锁是一种好方法。使用 Win32 API 中的互斥函数。(无论如何,.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 和 SYNC 标志,则调用方只能写入文件末尾,并且将忽略有关写入文件的任何偏移信息。但是,该文件将根据此类写入操作的需要自动扩展。

选项 3:锁定文件

您可以采取的另一条途径是使用 LockFile 方法。使用 LockFile(或 LockFileEx ),可以让两个应用程序打开文件,并让每个应用程序锁定要写入的文件部分。这为您提供了比互斥锁更多的粒度,允许同时进行非重叠写入。(对整个文件使用 LockFile 将提供与互斥锁相同的基本效果,但额外的好处是它将防止其他应用程序在您这样做时写入文件。在Raymond Chen的博客上有一个关于如何使用LockFile的很好的例子。

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

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

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

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