进程间并发文件写入

Concurrent File write between processes

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

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

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

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

不用atomic也可以。但是我需要知道与本地互斥锁相比,使用这个互斥锁是否会降低性能。

实际上您根本不需要使用单独的互斥体,您可以直接使用文件本身。当使用 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# 函数)。

为您的 C++ 应用程序添加 CLR 支持只是为了获得 Mutex class 是矫枉过正。您可以使用多种选项来同步两个应用程序之间的文件访问。

选项 1:互斥锁

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

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),则 OS将负责确保最后写入文件的所有数据,并且写入数据的两个应用程序不会相互覆盖。此行为记录在 MSDN:

If only the FILE_APPEND_DATA and SYNCHRONIZE flags are set, the caller can write only to the end of the file, and any offset information about writes to the file is ignored. However, the file will automatically be extended as necessary for this type of write operation.

选项 3:锁定文件

您可以采用的另一种方法是使用 LockFile 方法。用 LockFile (or LockFileEx), you can have both applications open the file, and have each app lock the section of the file that it wants to write to. This gives you more granularity than the mutex, allowing non-overlapping writes to happen at the same time. (Using LockFile on the entire file will give you the same basic effect as the mutex, with the added benefit that it will prevent other applications from writing the file while you're doing so.) There's a good example of how to use LockFile on Raymond Chen's blog.