如何使用Delphi管理EXE的多个实例对XML文件的并发输入/输出访问。
我有一个用Delphi编写的命令行工具,其作用是在XML文件中插入一个节点,然后立即退出。我需要使该工具的多个实例能够同时执行,并将节点插入到一个相同的XML中。
为了实现此目的,我引入了一个简单的文件" mutex",该工具在写入XML之前先创建一个临时文件,然后在完成所有操作后删除该临时文件。因此,如果执行了另一个实例,它将检查该临时文件的存在并等待直到将其删除。然后,它再次创建临时文件,写入XML并删除临时文件。
问题是,仅当2-3个实例尝试同时写入XML文件时,此方法才能正常工作。当有更多实例时,其中一些实例将永远等待,并且永远不要将节点添加到XML中。
是否有更好的方法使其与同时运行并写入XML的大量实例一起工作?
解决方案
1设置一个记录未决更改的文件(它将像队列一样工作)
2编写一个简单的应用程序来监视该文件,并将更改应用到XML文件
3修改当前的命令行工具,将其更改请求添加到"待更改"文件中
现在,只有一个应用程序必须触摸最终的XML文件。
TXMLDocument已经阻止多个实例同时写入同一文件。因此,我猜测问题的真正含义是:"如何打开XML文档以进行读取,如何防止其他实例在读取文档时将其写入文档,然后在允许其他实例做同样的事情?"
在这种情况下,我们应该自己处理文件的打开和关闭,而不是让TXMLDocument为我们完成。使用TFileStream使用排他的读写锁和XMLDocument.LoadFromStream而不是LoadFromFile打开文件。将流重置后,将文件保存到SaveToStream。位置为0。使用try / finally以确保在完成流后关闭流。由于我们仅锁定文件,因此不再需要临时文件或者任何其他类型的互斥锁。
显然,如果另一个实例当前正在读取/写入文件,则打开文件可能会失败。因此,我们需要处理此问题,然后稍后重试。
只需记住,每次需要添加节点时,都必须重新加载并重新分析整个文档。根据XML文档的大小以及要保存的数据,它可能不是传输数据的最有效方法。
写入单独文件的方法是一种有趣的解决方案,要考虑的一种方法是让"多个实例"应用程序编写唯一的XML文件,然后使用FindFirst循环使用单独的程序将它们加载到主文档中。这样,我们可以保持xml结构几乎完整,而无需对现有程序进行任何重大更改。
命名信号量或者互斥量可以在一台计算机上为我们完成此操作。使用例如来自SyncObjs的TMutex,并使用接受名称参数的构造函数之一。如果在所有应用程序中使用相同的名称,则它们将通过相同的内核互斥量进行同步。使用TMutex.Acquire进行访问,然后使用TMutex.Release,在try / finally块中进行保护。
使用具有InitialOwner参数的TMutex.Create重载,但是为此指定False(当然,除非我们想立即获取互斥体)。此重载在后台调用CreateMutex。在SyncObjs的源代码中以及CreateMutex的文档中查找更多详细信息。