2008-09-19 4 views
5

Ho uno strumento da riga di comando, scritto in Delphi, il cui compito è inserire un nodo in un file XML e quindi uscire immediatamente. Devo rendere possibile diverse istanze dello strumento da eseguire simultaneamente e inserire i nodi nello stesso XML.Come gestire l'accesso simultaneo Input/Output a un file XML da più istanze di un file EXE, utilizzando Delphi.

Per raggiungere questo scopo, ho introdotto un file "mutex" semplice: lo strumento crea un file temporaneo prima di scrivere nell'XML e quindi elimina il file temporaneo dopo aver finito di witing. Quindi, se viene eseguita un'altra istanza, verifica la presenza di questo file temporaneo e attende fino a quando non viene eliminato. Quindi crea nuovamente il file temporaneo, scrive nell'XML ed elimina il file temporaneo.

Il problema è che questo funziona bene solo quando 2-3 istanze provano a scrivere contemporaneamente nel file XML. Quando ci sono più istanze, alcune di esse attendono per sempre e non aggiungono mai il nodo all'XML.

Esiste un modo migliore per farlo funzionare con un numero elevato di istanze che eseguono e scrivono nell'XML allo stesso tempo?

+0

Grazie a tutti per le risposte finora. Per prima cosa ho avuto un errore logico nel mio codice e l'ho corretto, ma il metodo che uso non è ancora buono. Continuerò la prossima settimana su quel piccolo strumento e poi scriverò l'aggiornamento qui e accetterò la risposta più appropriata –

+0

Sembra che una soluzione client/server sia una buona soluzione qui ... –

risposta

6

Un semaforo o mutex denominato può farlo per voi su una singola macchina. Utilizzare per es. TMutex di SyncObjs e usa uno dei costruttori che accetta un argomento name. Se usi lo stesso nome in tutte le applicazioni, si sincronizzeranno sullo stesso mutex del kernel. Usa TMutex.Acquisisci per accedere e TMutex.Rilascia quando hai finito, protetto in un blocco try/finally.

Utilizzare il sovraccarico TMutex.Create, che ha un argomento InitialOwner, ma specificare false per questo (a meno che non si desidera acquisire il mutex subito, naturalmente). Questo sovraccarico chiama CreateMutex dietro le quinte. Cerca nella fonte SyncObjs e la documentazione per CreateMutex per ulteriori dettagli.

+0

Infine ho ricollegato a questo progetto, al mutex risolto il problema. 10x :) –

4

1 - impostare un file che registra modifiche in sospeso (che funzionerà come una coda)

2 - Scrivi una semplice applicazione per guardare quel file, e applicare le modifiche al file XML

3 - Modifica lo strumento da riga di comando corrente per aggiungere le loro richieste di modifica al file "Pending changes"

Ora solo un'app deve toccare il file XML finale.

+0

Probabilmente è più facile creare una directory in cui le modifiche richieste vengono aggiunte come file separati. Quindi non ci sono file da aggiungere, basta rilasciare ed eseguire. – mj2008

+0

Mi piace l'idea – JosephStyons

+0

Ma tutte le istanze devono scrivere nuovamente nello stesso file delle modifiche in sospeso. Questo inoltra il problema solo a un altro file. L'idea con la directory funzionerebbe davvero. –

2

TXMLDocument impedisce già più istanze di scrivere sullo stesso file contemporaneamente. Così sto cercando di indovinare che cosa il vostro domanda significa veramente è: "Come posso aprire un documento XML per la lettura, impedire ad altri casi di scrivere il documento mentre lo sto leggendo, e poi scrivere il documento prima di consentire altre istanze di fare la stessa cosa? "

In questo caso, è necessario gestire l'apertura e la chiusura del file da soli anziché consentire a TXMLDocument di eseguirlo automaticamente. Utilizzare TFileStream per aprire il file con un blocco di lettura e scrittura esclusivo e XMLDocument.LoadFromStream anziché LoadFromFile. Salva il documento con SaveToStream dopo aver ripristinato lo stream.Position su 0. Usa un try/finally per assicurarti di chiudere lo stream quando hai finito. Dato che stai bloccando esclusivamente il file, non hai più bisogno del file temporaneo o di alcun altro tipo di mutex.

Ovviamente, l'apertura del file potrebbe non riuscire se un'altra istanza sta attualmente leggendo/scrivendo su di essa. Quindi è necessario gestirlo e riprovare più tardi.

1

Basta ricordare che ogni volta che è necessario aggiungere un nodo, l'intero documento deve essere ricaricato e riorganizzato. A seconda delle dimensioni del documento XML e dei dati che si stanno salvando, potrebbe non essere il metodo più efficiente di trasferimento dei dati.

L'approccio di scrittura a un file separato è una soluzione interessante, da considerare sarebbe quella di avere le app "multiple instance" scrivere file XML univoci e quindi caricarli in un documento master con un programma separato utilizzando un ciclo FindFirst . In questo modo puoi mantenere la tua struttura xml praticamente intatta senza modifiche importanti ai tuoi programmi esistenti.

0

Da this answer:

In Windows, questo è possibile se è possibile controllare entrambi i programmi. LockFileEx. Per le letture, apri un blocco condiviso sul file di lock. Per le scritture, aprire un blocco esclusivo sul file di blocco. Il blocco è strano in Windows, , quindi per questo consiglio di utilizzare un file di blocco separato.

(dos 'Entrambi i programmi' non si applicano nel caso in questione è lo stesso programma, solo in esecuzione in istanze multiple.)

nota a margine/come ho trovato questa risposta: la biblioteca di registrazione Java logback usi l'API di blocco del file (NIO) per implementare lo 'prudent mode' in cui più processi possono accedere allo stesso file senza corromperlo, cosa che non è possibile con le operazioni di file RTL Delphi.

Problemi correlati