9
votes

Concurrent XMLreader et Xmlriter

J'ai un système qui crée des xmlreader et xmlwriter les cas et les transmet aux clients , afin que les clients puissent écrire et lire Xml.

Parfois, plusieurs threads accèdent au système:

  1. thread 1 obtient un xmlwriter instance et commence à écrire
  2. thread 2 obtient un xmlreader instance représentant le même document XML et commence la lecture.

    Évidemment, le lecteur commence parfois à lire avant que l'écrivain ait terminé l'écriture, ce qui cause une exception à lancer dans le lecteur:

    system.xml.xmexception: l'élément racine est manquant.

    Ce n'est pas particulièrement surprenant, mais y a-t-il un moyen de faire ce système-sécurité?

    • est-il possible de faire lire le lecteur pendant que l'auteur écrit? J'ai essayé d'utiliser un MemoryReam en tant que magasin de données sous-jacent, mais cela ne semblait pas fonctionner.
    • est-il possible de rendre le lecteur attendre jusqu'à ce que l'auteur ait terminé l'écriture?
    • est-il possible de détecter que l'auteur écrit toujours?

      L'une des approches ci-dessus serait, je crois, résoudre mon problème. Il n'est pas nécessaire que l'écriture et la lecture se produisent simultanément. En fait, je serais parfaitement heureux si je pouvais simplement dire au client demander le xmlreader que le lecteur n'est pas encore prêt, et il doit réessayer plus tard. Cependant, cela nécessite qu'il y ait un moyen de détecter que l'auteur écrit toujours.

      J'ai le contrôle total sur le code qui crée le xmlreader et xmlwriter , mais je ne peux pas changer l'API publique. Je peux utiliser un chaîne , un stringbuilder , un MemoryStream ou tout autre objet en mémoire qui obtiendra le travail effectué, comme le stockage sous-jacent et je peux utiliser toute classe dérivée de xmlreader et xmwriter .

      Y a-t-il un moyen de faire ce système de sécurité?


7 commentaires

Vous devez créer un mécanisme de commande / checkin.


Vous pouvez probablement créer votre propre flux qui servirait de fournisseur à votre lecteur / écrivain XML, et il bloquera une opacité de lecture jusqu'à ce qu'il sait que toutes les écrivies sont terminées. Une fois que l'écriture est survenue, débloquer lire et procéder heureusement. Vous pouvez probablement toujours utiliser Morthstream comme support sur votre flux personnalisé.


Lorsque vous dites "clients" parlez-vous plusieurs processus? (s'il vous plaît dites-moi non).


@PeterRitchie Non, juste d'autres objets dans le même processus (mais sur différents threads).


@ LB2: Le blocage du niveau du flux peut être insuffisant, car le flux n'a aucune idée du moment où une opération est réellement complète.


Ouf, un RWL sonne exactement ce dont vous avez besoin.


@Adamrobinson basé sur "est-il possible de faire attendre le lecteur jusqu'à ce que l'écrivain ait terminé l'écriture?" Il semble que le contenu est petit, alors on peut attendre que XMLWriter est fermé et la détecter par elle fermant le flux sous-jacent, ce qui servirait de signal pour débloquer le flux de lecture. Mais je suis d'accord avec un commentaire plus tard que RWL est probablement ce que OP est vraiment recherché.


6 Réponses :


7
votes

Votre meilleur pari est probablement de créer des classes personnalisées qui dérivent de xmlreader et xmwriter . Vous pouvez leur ajouter un objet de synchronisation commune et utiliser quelque chose comme un readwriterlockslim pour coordonner la lecture et l'écriture. Vous devriez déterminer dans la classe d'écrivain ce que vous voulez dire lorsque vous dites que c'est «fait» (disposé »(DONE? Fait écrit un noeud unique, même si ce n'est pas complètement fait? Etc.)

Vous pouvez alors simplement faire les méthodes dans le bloc de lecteur jusqu'à ce que l'écriture ne soit pas en cours.


1 commentaires

Merci, cette solution était tout ce dont j'avais besoin. En fait, je pourrais obtenir uniquement la création d'une classe dérivée de xmlwriter , qui comprenait un rappel lors de son élimination. Jusqu'à ce que le rappel survient, je dis simplement aux lecteurs que le document n'est pas encore prêt, puis lorsque le rappel est disponible, le document devient disponible.



0
votes

Une idée simple est de créer un dictionnaire (éventuellement statique) de documents en cours d'écriture. Bien que ce document soit dans ce document, les demandes de lecture du dictionnaire sont bloquées ou rejetées.


0 commentaires

-2
votes

Bonne idée Il est de créer une copie de fichier XML dans un verrou qui affectait également sur un xmlwriter.

code de l'écrivain: xxx

code de lecteur: xxx


1 commentaires

Pourquoi copier si vous verrouillez le fichier?



2
votes

On dirait que vous avez besoin de quelque chose de similaire à la pipedrader / pipedWriter en Java. http://docs.oracle.com/javase/ 7 / DOCS / API / JAVA / IO / PIPEDREADER.HTML . On dirait que .NET n'a rien de tel: Les équivalents de Java de PipeDreader / VoipedWriter en C # ? .

Vous pouvez faire la même chose que dans Java en implémentant votre propre système.IO.TextWriter et System.IO.TexTreader à l'aide de ce code Java comme base:

http://grepcode.com/file_/Repository.grepcode.com/java/root/jdk/openjdk/7-B147/java/io/pipedreader.java/?v=Source

http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/7-B147/java/io/pipèdewriter.java/?v=Source


1 commentaires

Cela ressemble à la solution générale correcte à ce type de problème (SO +1). J'espérais que cela a déjà été construit dans la BCL et que j'avais juste négligé quelque chose d'évident, mais cela semble ne pas être le cas. Cependant, comme cette solution suggérée est plutôt complexe et que je pouvais gérer avec une solution plus simple, j'ai sélectionné une autre réponse comme «la» réponse. Merci.



3
votes

Qu'est-ce que vous recherchez est un flux qui permet à un fil d'écrire tandis que l'autre lit. Le .NET Framework ne fournit pas une telle chose. Vous pouvez potentiellement le faire avec un tuyau nommé, mais j'ai trouvé ce lourd. J'ai donc écrit ce que j'ai appelé un producteur producteur . C'est juste une file d'attente circulaire enveloppée dans une interface . Voir Construire un nouveau type de flux pour une description et une source complète .

pour l'utiliser avec xmlwriter et xmlreader , vous feriez quelque chose comme ceci: xxx

le Le thread de producteur créerait un xmlwriter qui écrit au flux: xxx

Le thread de lecteur est similaire: xxx

Assurez-vous que dans vos paramètres de l'écrivain, vous définissez fermerOutput = false , et dans le jeu de paramètres de lecteur fermerInput = false . Sinon, le flux pourrait être éliminé prématurément.

La clé ici est que producteur producteur.fread bloque jusqu'à ce qu'il puisse lire des données. Sauf si la fin du flux n'a été signalée en appelant en terminaison .

comprendre, il s'agit d'une structure en mémoire. Si vous souhaitez persister le XML aussi, vous devrez le faire d'une autre manière. Bien que je suppose que vous pouvez dériver de producteur producteur et remplacer la méthode de sorte que cela sortit sur le fichier ainsi que la copie des choses sur le tampon interne.


1 commentaires

Cela ressemble à la solution générale correcte à ce type de problème (SO +1). J'espérais que cela a déjà été construit dans la BCL et que j'avais juste négligé quelque chose d'évident, mais cela semble ne pas être le cas. Cependant, comme cette solution suggérée est plutôt complexe et que je pouvais gérer avec une solution plus simple, j'ai sélectionné une autre réponse comme «la» réponse. Merci.



2
votes

est-il possible de rendre le lecteur attendre jusqu'à ce que em> l'auteur ait terminé l'écriture? P>

Oui avec un Construction de la synchronisation de fil hybride , par ex. ManualReseteventsLIM , comme suit: P> XXX PRE>

Sortie de la console: P>

private static void CreateXmlDocument(XmlWriter writer)
{
    writer.WriteStartDocument();
    writer.WriteStartElement("Product");
    writer.WriteAttributeString("ID", "001");
    writer.WriteAttributeString("Name", "Soap");
    writer.WriteElementString("Price", "10.00");
    writer.WriteStartElement("OtherDetails");
    writer.WriteElementString("BrandName", "X Soap");
    writer.WriteElementString("Manufacturer", "X Company");
    writer.WriteEndElement();
    writer.WriteEndDocument();
}


2 commentaires

Cette solution s'appuie sur la synchronisation chez le client. Cependant, je cherche une solution qui ne nécessite pas que les clients soient synchronisés, car l'écrivain et le lecteur ne peuvent avoir aucune connaissance de l'autre.


Oh, je vois ... J'ai mis l'accent sur le fait que vous avez le contrôle total sur le code qui crée le xmlreader et xmwriter instances.