Meilleure façon de filet rapport de progrès
J'ai un programme qui utilise des threads pour effectuer de longs processus de manière séquentielle. Je veux être en mesure de suivre les progrès de chaque thread similaire à la façon dont le BackgroundWorker.ReportProgress
/ProgressChanged
modèle ne. Je ne peux pas utiliser ThreadPool
ou BackgroundWorker
en raison d'autres contraintes, je suis sous. Quel est le meilleur moyen pour permettre/exposer cette fonctionnalité. La surcharge de la Thread
classe et ajouter une propriété/événement? Une autre plus-solution élégante?
- Comment êtes-vous créer les threads?
- Steve Townsend - je avoir une usine qui crée tous à l'avance et d'une machine à état qui contrôle le moment où ils sont exécutés.
- Quelles sont les contraintes? Pouvez-vous créer une classe à enrouler un Fil et de l'utilisation de cette classe? C'est l'Objet Actif motif.
- Henry - Merci pour le modèle de conception de nom, je suis encore à apprendre/nouveau pour eux. Les contraintes sont que j'ai besoin d'être en mesure de s'assurer que certains threads s'exécutent concurremment & certains fils sont exécutées de manière séquentielle (par rapport à d'autres) en fonction du type de leur tâche et de l'information supplémentaire fournie (essentiellement d'une matrice de threads). Je pense que la classe wrapper est ma meilleure option, mais peut-être plusieurs BackgoundWorkers n'autorisant qu'un seul élément de travail pourrait également être une option.
- Utiliser un autre composant BackgroundWorker pour chaque fil que vous souhaitez exécuter simultanément. L'utilisation d'un seul composant BackgroundWorker pour les travaux que vous souhaitez exécuter en séquence. En fait, dans la WorkCompleted handler, vous pouvez mettre en place la prochaine BackgroundWorker pour s'exécuter. Aussi, si vous êtes en utilisant .NET 4 regarder le Système.Le filetage.Les tâches de l'espace de noms.
Vous devez vous connecter pour publier un commentaire.
Si par "surcharge" vous fait dire héritent alors non. Le
Thread
est scellé de sorte qu'il ne peut pas être héritée ce qui signifie que vous ne serez pas en mesure d'ajouter des propriétés ou des événements.Créer une classe qui encapsule la logique qui sera exécuté par le thread. Ajouter une propriété ou un événement (ou les deux) qui peut être utilisé pour obtenir des informations sur la progression de lui.
Mise à jour:
Permettez-moi d'être un peu plus clair sur les raisons d'une barrière de mémoire est nécessaire dans cette situation. La barrière empêche la lecture ne soit déplacé avant que d'autres instructions. Les plus susceptibles d'optimisation n'est pas le PROCESSEUR, mais de le compilateur JIT "lifting" de la lecture des
Progress
à l'extérieur de lawhile
boucle. Ce mouvement donne l'impression de "rassis", lit -. Ici, c'est un semi-réaliste démonstration du problème.Il est impératif qu'un Communiqué de construire est déroulée sans le vshost processus. Soit on désactive l'optimisation que manifeste le bug (je crois que ce n'est pas reproduit dans le cadre de la version 1.0 et 1.1, en raison de leur plus primitive optimisations). Le bug, c'est que "Arrêté" n'est jamais affiché, même si elle devrait à l'évidence être. Maintenant, commentaire l'appel à
Thread.MemoryBarrier
et notez le changement de comportement. Aussi garder à l'esprit que même les plus subtils changements dans la structure de ce code actuellement inhiber la capacité du compilateur pour faire de l'optimisation en question. Un tel changement serait d'invoquer le délégué. En d'autres termes vous ne pouvez pas actuellement reproduire la lecture obsolète problème à l'aide de l'null vérifier suivie par une invocation modèle, mais il est rien dans la spécification CLI (que je suis au courant de toute façon), qui interdit à un avenir hypothétique compilateur JIT de réappliquer cette "levée" d'optimisation.var local = ...
stackoverflow.com/questions/1773680/...Progress
lire est frais toujours (pas de prochaine fois, mais maintenant). Je me fous de savoir si lethis
etargs
lit sont levées à l'extérieur de laif
déclaration et au-dessus de laProgress
lire. Par ailleurs, j'aurais pu utiliser unlock
, mais un programmeur naïf pourrait supprimer plus tard parce qu'il est apparu inutile. C'est l'un des rares scénarios où j'ai vraiment recommanderThread.MemoryBarrier
parce qu'il permet l'intention clairement évident.Progress
à chaque itération de la boucle, même sans le consentement de la barrière. Mais, il n'y a pas de gage.Main()
, aprèsvar local = GetEvent();
et un dans lewhile
boucle, aprèslocal = GetEvent();
. Cela peut être exprimé dansGetEvent()
en mettant un membar entre la mission et le retour des déclarations.VolatileRead()
serait.(si il y a une surcharge pour les événements....)local
peut être optimisé à l'écart. Ce serait traduitif (Progress != null) Progress()
qui n'est clairement pas ce qui est prévu. Juste pour ajouter un autre grand Joe Duffy post: bluebytesoftware.com/blog/2008/06/13/...volatileread
ne et de le mettre à la bonne place.local
arriver optimisé loin est la clé ici. Et je vois votre point de vue. Ce n'est certainement pas quelque chose que je pensais. J'étais plus axé sur la lecture de la "levée" à l'extérieur de la boucle. Il semble que doit être une barrière entre le lire et de le vérifier. Mais, si vous déplacez simplement, vous permettent aujourd'hui à la lecture initiale deProgress
à "lever" de droite? Je vais aller de l'avant et modifier mon exemple pour inclure une clôture sur les deux côtés de la lire. Qui va fixer le tout et il en reste encore plus d'auto documentation que d'un cas isolélock
déclaration.Thread.MemoryBarrier
(l'un au-dessus de la lecture) est supprimée, car seul la première lecture de à être obsolète, mais une fois que la boucle sautes de retour autour de la deuxième fois qu'un "refresh" aurait dû avoir lieu. Je suis totalement avec vous sur ce point.J'ai essayé il y a quelques temps et il a travaillé pour moi.
List
-comme la classe avec des serrures.Timer.Tick
événement pour lire les messages que les fils de sortie.Vous pourriez également vouloir vérifier la Basé sur des événements du Modèle Asynchrone.
Fournir à chaque thread avec un rappel qui renvoie à un état d'objet. Vous pouvez utiliser le thread
ManagedThreadId
de garder une trace des threads séparés, tels que de l'utiliser comme une clé pour unDictionary<int, object>
. Vous pouvez appeler la fonction de rappel à partir de nombreux endroits dans le fil de la boucle de traitement ou d'appeler à partir d'un timer déclenché depuis le thread.Vous pouvez également utiliser le retour d'argument à une fonction de rappel pour signaler le fil pour mettre en pause ou stopper les.
J'ai utilisé des rappels avec grand succès.