views:

841

answers:

4

I have a command line tool, written in Delphi, which job is to insert a node in a XML file and then immediately exit. I need to make it possible several instances of the tool to be executed simultaneously and insert nodes to one and the same XML.

To achieve this purpose I have introduced a simple file "mutex" - the tool creates one temp file before writing to the XML and then deletes the temp file after finished witing. So if another instance is executed, it checks for the presence of this temp file and waits until it is deleted. Then it creates again the temp file, writes to the XML and deletes the temp file.

The problem is that this works fine only when 2-3 instances try to write to the XML file simultaneously. When there are more instances - some of them just wait forever and never append the node into the XML.

Is there a better way to make it work with large number of instances running and writing to the XML at the same time?

+4  A: 

1 - Set up a file which records pending changes (it will work like a queue)

2 - Write a simple app to watch that file, and apply the changes to the XML file

3 - Modify the current command-line tool to append their change requests to the "Pending changes" file

Now only one app has to touch the final XML file.

JosephStyons
Probably easier to create a directory into which the required changes are added as separate files. Then there is no file to append to, just drop and run.
mj2008
I like that idea
JosephStyons
But all instances should write again to the same pending changes file. This only forwards the problem to another file. The idea with the directory would actually work.
m_pGladiator
+1  A: 

TXMLDocument already prevents multiple instances from writing to the same file simultaneously. So I'm guessing that what your question really means is, "How can I open an XML document for reading, prevent other instances from writing to the document while I'm reading it, and then write to the document before allowing other instances to do the same thing?"

In this case, you should handle opening and closing the file yourself rather than allowing TXMLDocument to do it for you. Use a TFileStream to open the file with an exclusive read and write lock and XMLDocument.LoadFromStream instead of LoadFromFile. Save the document with SaveToStream after resetting the stream.Position to 0. Use a try/finally in order to ensure that you close the stream when you are done with it. Since you're exclusively locking the file, you no longer need the temp file or any other kind of mutex.

Obviously, opening the file could fail if another instance is currently reading/writing to it. So you need to handle this and retry later on.

Craig Stuntz
+1  A: 

Just remember that every time you need to add a node, the entire document must be reloaded and reparsed. Depending on the size of the XML document and what data you are saving, it might not be the most efficient method of transferring data.

The approach of writing to a separate file is an interesting solution, one to consider would be to have your "multiple instance" apps write unique XML files and then load those into a master document with a separate program using a FindFirst loop. That way you can keep your xml structure pretty much intact without any major changes to your existing programs.

skamradt
+4  A: 

A named semaphore or mutex can do this for you on a single machine. Use e.g. TMutex from SyncObjs, and use one of the constructors which takes a name argument. If you use the same name in all the applications, they will be synchronizing over the same kernel mutex. Use TMutex.Acquire to access, and TMutex.Release when you're done, protected in a try/finally block.

Use the TMutex.Create overload which has an InitialOwner argument, but specify False for this (unless you want to acquire the mutex straight away, of course). This overload calls CreateMutex behind the scenes. Look in the source to SyncObjs and the documentation for CreateMutex for extra details.

Barry Kelly
Finally I looped to this project again, at the mutex solved the problem. 10x :)
m_pGladiator