Ici, je suis à nouveau avec des questions sur le multi-threading et un exercice de ma catégorie STRAND> Chant de programmation forte>.
J'ai un serveur multi-threadé - implémenté en utilisant le modèle de programmation .NET asynchrone em> - avec Il arrive que le relevé du problème indique que ce serveur doit avoir em> l'activité em> avec l'impact minimum sur le temps de réponse du serveur, et il devrait être Pris en charge par une priorité basse thread em> - thread de l'enregistreur em> - créé pour cet effet. Tous les em> les messages em> doivent être passés par les threads em> qui les produisent à cet le fil d'enregistreur em>, à l'aide d'un mécanisme de communication que ne peut pas fort> verrouillez le fil em> qui l'invoque (en plus du verrouillage nécessaire pour assurer l'exclusion mutuelle) et en supposant que certains les messages de journalisation em> peuvent être ignorés. P> ici Est-ce que ma solution actuelle, s'il vous plaît aider à la validation si cela constitue une solution au problème indiqué: p> essentiellement, voici les points principaux de ce code: P> < ol>
est cette solution thread-coffre em>? J'ai lu les producteurs-consommateurs em> algorithme de problèmes et de solution, mais dans ce problème, bien que j'ai plusieurs producteurs, je n'ai qu'un seul lecteur. P> p> obtenez code> ( télécharger em>) et
mettre code> ( téléchargez em>). Cette partie est effectuée et testée. P>
4 Réponses :
En fait, vous introduisez le verrouillage ici. Vous avez le verrouillage lorsque vous appuyez sur une entrée de journal dans la file d'attente (méthode du journal): Si 10 threads ont poussé simultanément 10 éléments dans la file d'attente et réveillés le fil de l'enregistreur, le 11ème thread sera attendu jusqu'à ce que le fil de l'enregistreur enregistre tous les articles ... P >
Si vous voulez quelque chose de vraiment évolutif - implémenter la file d'attente sans verrouillage (l'exemple est ci-dessous). Avec le mécanisme de synchronisation de la file d'attente sans verrouillage sera vraiment tout de suite (vous pouvez même utiliser une seule poignée d'attente unique pour les notifications). P>
Si vous ne parvenez pas à trouver la mise en œuvre de la file d'attente sans verrouillage sur le Web, voici une idée de comment faire ceci: Utilisez la liste liée pour une implémentation. Chaque nœud de la liste liée contient une référence em> et une référence volatile au nœud suivant. Par conséquent, pour les opérations Enqueue et Dequeue, vous pouvez utiliser la méthode Interlocked.comPareExchange. J'espère que l'idée est claire. Si non - laissez-moi savoir et je vais fournir plus de détails. P>
Salut. Merci beaucoup pour votre réponse, mais j'aimerais vraiment éviter une solution qui utilise des mécanismes verrouillés. Il est dit dans la déclaration d'exercice que je peux utiliser le verrouillage, bien que des fins d'exclusion mutuelle. Je ne peux pas envisager le mécanisme "de verrouillage" de ma solution pour correspondre à cet objectif, car je suis simplement en train d'essayer d'assurer l'exclusion mutuelle accédant à la file d'attente de journalisation?
@XPIRITOO: Vous ne pouvez effectuer aucun travail sans verrouillage multiprocesseur sans verrouillage sans verrouillage sans les instructions verrouillées (ni leurs équivalents de GCC). Si vous utilisez un verrou de mutex, vous n'avez pas besoin de verrouillés. Mais la suggestion de Vitaliy était de construire une file d'attente sans verrouillage.
OK, si vous n'avez pas besoin d'exigences de performance critiques - votre code au premier aspect a l'air de thread-coffre-fort.
Il semble que cela devrait fonctionner. Les producteurs-consommateurs ne devraient pas changer grandement en cas de consommateur unique. Petits nitpicks: p>
Acquisition de verrouillage peut être une opération coûteuse (comme @Vitaliy Lipchinsky dit). Je recommanderais de comparer votre enregistreur contre l'enregistreur et l'enregistreur naïfs "écriture" à l'aide d'opérations imbriquées. Une autre alternative n'échangerait que la file d'attente existante avec un vide vide dans Mme LogOBJ Type de référence (classe). Il ne sert à rien de faire la structure car vous la boxez de toute façon. Ou bien faire Faites votre fond de fil de manière à éviter de fermer votre programme si Flush votre Implément Idisposable et / ou finisseur. Votre enregistreur possède un fil de fil et de texte et ceux-ci devraient être libérés (et rinçage - voir ci-dessus). P> li>
ul> getlog code> et quittant la section critique immédiatement. Cette façon aucune des producteurs ne sera bloquée par de longues opérations dans les consommateurs. P> li>
_Queue code> de type
logOBJ [] code> (c'est mieux quand même). p> li>
stop code> ne sera pas appelé. p> li>
TextWriter code>. Ou sinon vous risquez de perdre même ces enregistrements qui ont géré la file d'attente (10 articles sont un peu petit IMHO) p> li>
Merci pour vos considérations. Va certainement changer mon code en conséquence.
Bien que cela semble être le fil-coffre-fort, je ne crois pas qu'il est particulièrement optimal. Je suggérerais une solution sur ces lignes
Salut. Merci de m'avoir souvenu de moi d'utiliser une terminaison de fil gracieuse, au lieu d'une méthode de "Abandon" puissante. Je vais absolument adopter ça!
Au début, je n'ai pas remarqué des problèmes que j'ai trouvés dans votre code, lorsque j'ai essayé d'adapter ma solution à la suite de vos suggestions. En fait, vous ne pouvez pas "pulser" ou "attendre" sur un objet de synchronisation en dehors de la portée "verrouille" correspondante. Considérant cela, il n'y a pas de gain sur la création d'une copie locale de la file d'attente de l'enregistreur sur votre méthode "getLog"; Il n'est pas non plus possible de réduire l'acquisition de verrouillage sur la file d'attente, dans votre méthode de «journal». En outre, certaines méthodes que vous faites référence n'existent pas. La file d'attente n'a pas de méthode "Tolist ()" (seulement un "toarray ()") et "moniteur.pulse ()" doit recevoir un paramètre (objet de synchronisation) ...
Ahem, leçon importante, jamais "aile" une réponse. L'utilisation d'un moniteur [correctement] est synchronisée avec l'utilisation de la serrure. Puisque nous utilisons le verrouillage pour protéger notre file d'attente, le moniteur est totalement superflu. Supprimez-le [à partir de deux solutions ci-dessus et \ ou votre solution précédente]. Ce n'est pas nécessaire. Il y a beaucoup de gain de créer une copie locale de la file d'attente. N'effectuez jamais de traitement dans une section critique. Vous souhaitez accéder à votre ressource partagée et publiez-la. Traitement [c'est-à-dire l'écriture à la console, le fichier, le RPC, tout ce que] peut être effectué ultérieurement. Tolist est une méthode d'extension disponible dans .NET3.5, à l'aide de System.Linq
Eu, par "aile" une réponse, faisait référence à moi évidemment. aurait dû rechercher le moniteur plus tôt, aurait repéré la redondance. : S
Je fais juste une expérience de pensée ici, car je n'ai pas le temps d'essayer le code en ce moment, mais je pense que vous pouvez le faire sans serrures du tout si vous êtes créatif. P>
Demandez à votre classe de journalisation contenant une méthode qui alloue une file d'attente et un sémaphore à chaque fois qu'elle s'appelle (et une autre qui transmet la file d'attente et le sémaphore lorsque le fil est effectué). Les threads qui souhaitent faire la journalisation appelleront cette méthode lorsqu'ils commencent. Quand ils veulent se connecter, ils poussent le message à leur propre file d'attente et définissent le sémaphore. Le fil de l'enregistreur a une grosse boucle qui traverse les files d'attente et vérifie les sémaphores associés. Si le sémaphore associé à la file d'attente est supérieur à zéro, la file d'attente est apparue et le sémaphore décrémenté. P>
Parce que vous n'essayez pas de faire sortir les choses de la file d'attente avant que le sémaphore soit défini, et que vous ne définissez pas le sémaphore qu'après avoir poussé les choses sur la file d'attente, je pense em> Ce sera en sécurité. Selon la documentation MSDN pour la classe de file d'attente, si vous énumérez la file d'attente et un autre thread modifie la collection, une exception est lancée. Attraper cette exception et vous devriez être bon. P>