简体   繁体   English

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

[英]Write reliably to same file from different processes

I did create a small C++ Tracing solution which works very well. 我确实创建了一个很好的小型C ++跟踪解决方案。 Within one process all is well but when I open the output file from diferent processes the data gets not correctly written. 在一个进程中一切都很好但是当我从不同的进程打开输出文件时,数据没有被正确写入。 I did open the file with FILE_SHARE_WRITE to be able to write to the file when it is already open. 我确实用FILE_SHARE_WRITE打开文件,以便在文件打开时写入文件。 Then I did create a named mutex to ensure proper synchronisation between processes. 然后我创建了一个命名的互斥锁,以确保进程之间的正确同步。 But it appears that this is not enough. 但似乎这还不够。 According to the MSDN this does work within one process but not between different processes. 根据MSDN,这确实在一个过程中起作用,但在不同过程之间起作用。 Next I tried to call FlushFileBuffers after every write while the mutex was still held but data was still distorted like this 接下来我尝试在每次写入后调用FlushFileBuffers,而互斥锁仍被保持,但数据仍然像这样扭曲

The format is time process id/Thread id method enter/leave/severity namespace+method and then the message text. 格式是时间进程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

I have looked at FILE_FLAG_NO_BUFFERING but it has severe limitations and it seems not easy to use . 我查看了FILE_FLAG_NO_BUFFERING,但它有严重的限制,似乎不容易使用

Does anybody know the right way to write synchronized to the same file without distoriting the output? 有没有人知道在不降低输出的情况下将同步写入同一文件的正确方法?

Yours, 此致,

Alois Kraus Alois Kraus

I finally got it working. 我终于搞定了。 The trick was to Seek at the end of the file before very write. 诀窍是在写入之前先找到文件的末尾。 Otherwise I would overwrite about half of my output although I do lock with a cross process mutex before every write. 否则我会覆盖大约一半的输出,尽管我在每次写入之前都会使用跨进程互斥锁。

The code looks like this 代码看起来像这样

__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);
    }
}

SQLite uses file locks to ensure this doesn't happen to its database file when accessing it from multiple processes. SQLite使用文件锁来确保从多个进程访问它时不会发生这种情况。 Have you tried using LockFile ? 你尝试过使用LockFile吗? ( example ). 例子 )。 I have, in the past, used an SQLite database for logging from multiple processes, but then that's probably a bit too much in this case. 在过去,我使用SQLite数据库从多个进程进行日志记录,但在这种情况下,这可能有点太多了。

I don't know about the "right" way, but what you're doing already seems as right as it gets to me. 我不知道“正确”的方式,但你所做的事情似乎已经对我有用了。 The next possible solution that I can think of would be a dedicated process for writing to this file. 我能想到的下一个可能的解决方案是写入此文件的专用过程。 The rest of the processes would communicate with the log-process through named pipes and (possibly) mutexes. 其余的进程将通过命名管道和(可能)互斥体与日志进程通信。

Perhaps you can even set it up so that there is no explicit process, but one of the running processes (the one which was started first) takes on this role. 也许您甚至可以将其设置为没有显式进程,但其中一个正在运行的进程(首先启动的进程)承担此角色。 There would, of course, be further complications when this process ends and needs to pass the ownership of the file to another process. 当然,当这个过程结束并且需要将文件的所有权传递给另一个进程时,会有进一步的复杂化。 All in all it's not a very pretty solution, but it should work if all else fails. 总而言之,这不是一个非常漂亮的解决方案,但如果所有其他方法都失败了它应该可以工作。

Although I would suspect that there is still something neither of us has thought about, because there are programs which successfully use files for communication. 虽然我怀疑我们还没有想到的东西,因为有些程序可以成功地使用文件进行通信。

Hmm... on second thought - you already have timestamps available. 嗯......第二个想法 - 你已经有了时间戳。 Why not just make a browsing tool which sorts the records by timestamps? 为什么不制作一个按时间戳对记录进行排序的浏览工具? That way it would not matter what gets cached where. 这样,将缓存放在哪里并不重要。

Oh, and a third though - have you tried memory-mapped I/O? 哦,还有第三个 - 你有没有尝试过内存映射的I / O? That's organized differently and it might be able to solve your problem (not to mention be more efficient). 这是有组织的,它可能能够解决您的问题(更不用说更有效)。

As a starting point, I'd suggest ditching the shared write mode and making use of your named mutex to manage exclusive access to the file. 作为一个起点,我建议放弃共享写入模式并利用您的命名互斥锁来管理对文件的独占访问。 If everything's working as it should, this should give you correct output. 如果一切正常,这应该给你正确的输出。 Then do some performance testing to see if you can afford to operate like this - you might find it's sufficient. 然后做一些性能测试,看看你是否能负担得起这样的操作 - 你可能会发现它已经足够了。

You have to protect or synchronize concurrent calls to the function that writes into the file with a named mutex. 您必须保护或同步对使用命名互斥锁写入文件的函数的并发调用。 See CreateMutex 请参见CreateMutex

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM