可靠地写入来自不同进程的同一文件

Alo*_*aus 8 c c++ windows winapi

我确实创建了一个很好的小型C++跟踪解决方案.在一个进程中一切都很好但是当我从不同的进程打开输出文件时,数据没有被正确写入.我确实用FILE_SHARE_WRITE打开文件,以便在文件打开时写入文件.然后我创建了一个命名的互斥锁,以确保进程之间的正确同步.但似乎这还不够.根据MSDN,这确实在一个过程中起作用,但在不同过程之间起作用.接下来我尝试在每次写入后调用FlushFileBuffers,而互斥锁仍被保持,但数据仍然像这样扭曲

格式是时间进程id /线程id方法输入/ leave/severity命名空间+方法然后是消息文本.

10:29:42.994 7448/2236       }} Dll2.Test.fndll2 L1 -> Duration: 0.094s
10:29:43.040 7448/2236 {{       Dll2.DllMain L1
10:29:43.134 7448/2236 Info     Dll2.DllMain L1 Process detach
10:29:43.181 7448/2236       }} Dll2.DllMain L1 -> Duration: 0.141s
     }} Dll2.DllMain L1 -10:29:42.681 7448/2236 Info     Dll1.DllMain L1 Process attach
10:29:42.728 7448/2236       }} Dll1.DllMain L1 -10:29:42.744 2216/5510:29:42.775 7448/2236 {{       Dll1.Test.fndll1 10:210:29:42.822 7448/2236 Info     Dll1.Test.fndll1 10:29:42.837 2216/557610:29:42.853 7448/2236       }} Dll1.Test.fndll1 L110:29:42.884 2216/557610:29:43.306 7448/2236 {{       Dll1.DllMain L1
10:29:43.353 7448/2236 Info     Dll1.DllMain L1 Process detach
10:29:43.400 7448/2236       }} Dll1.DllMain L1 -> Duration: 0.094s
Run Code Online (Sandbox Code Playgroud)

我查看了FILE_FLAG_NO_BUFFERING,但它有严重的限制,似乎不容易使用.

有没有人知道在不降低输出的情况下将同步写入同一文件的正确方法?

此致,

Alois Kraus

Alo*_*aus 7

我终于搞定了.诀窍是在写入之前先找到文件的末尾.否则我会覆盖大约一半的输出,尽管我在每次写入之前都会使用跨进程互斥锁.

代码看起来像这样

__int64 Seek (HANDLE hf, __int64 distance, DWORD MoveMethod)  // from MSDN 
{
   LARGE_INTEGER li;
   li.QuadPart = distance;
   li.LowPart = SetFilePointer (hf, 
                                li.LowPart, 
                                &li.HighPart, 
                                MoveMethod);

   if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
   {
      li.QuadPart = -1;
   }

   return li.QuadPart;
}



void WriteToFile(TCHAR *pData)
{
    DWORD dwWritten = 0;

    if( FALSE == ::WriteFile(_hFile, pData, _tcslen(pData)*sizeof(TCHAR), &dwWritten, NULL) )
    {
        _LastError = ::GetLastError();
        ASSERT__(FALSE);
    }
}

virtual void Write(TCHAR *pStr)
{
    if( _hWriteMutex != NULL )
    {
        DWORD res = ::WaitForSingleObject(_hWriteMutex, 120*1000);
        if( res == WAIT_OBJECT_0 || res == WAIT_ABANDONED ) // another process might have crashed while holding the mutex
        {
            // Ensure that we are really writing at the end of the file 
            __int64 fPos = Seek(_hFile, 0, FILE_END);
            WriteToFile(pStr);
            ::ReleaseMutex(_hWriteMutex);
        }
        else
        {
            ASSERT__(FALSE);
        }
    }
    else
    {
        WriteToFile(pStr);
    }
}
Run Code Online (Sandbox Code Playgroud)


Vil*_*lx- 0

我不知道“正确”的方式,但你正在做的事情对我来说已经是正确的了。我能想到的下一个可能的解决方案是写入此文件的专用进程。其余进程将通过命名管道和(可能)互斥体与日志进程进行通信。

也许您甚至可以将其设置为不存在显式进程,但正在运行的进程之一(第一个启动的进程)承担此角色。当然,当该进程结束并需要将文件的所有权传递给另一个进程时,会出现进一步的复杂情况。总而言之,这不是一个非常漂亮的解决方案,但如果其他方法都失败了,它应该可以工作。

尽管我怀疑还有一些我们都没有想到的事情,因为有些程序成功地使用文件进行通信。

嗯...再想一想 - 你已经有了可用的时间戳。为什么不直接制作一个按时间戳对记录进行排序的浏览工具呢?这样,什么内容缓存在哪里就无关紧要了。

哦,还有第三个——你尝试过内存映射 I/O 吗?这是以不同的方式组织的,它可能能够解决您的问题(更不用说更有效率)。