Dans quelles circonstances la mise à jour d'une commande d'interface utilisateur d'un thread non-UI pourrait entraîner une augmentation continuellement des processus d'augmenter continuellement, lors de l'utilisation d'un délégué et de Par exemple: p> Lorsque ceci est appelé dans une boucle ou sur des intervalles de minuterie, les poignées du programme augmentent systématiquement. P> EDIT: strong> si ce qui précède est commenté et modifié en tant que tel: p> ... puis les poignées arrêt em> incrémentation, cependant je Ne voulez pas autoriser les appels de threads croisés, bien sûr. P> Voici un échantillon qui montre les poignées augmentant: P > .invokéréquitéd code>?
Thread thread;
private delegate void UpdateGUI();
bool UpdateTheGui = false;
public Form1()
{
InitializeComponent();
thread = new Thread(new ThreadStart(MyThreadLoop));
thread.Start();
}
private void MyThreadLoop()
{
while (true)
{
Thread.Sleep(500);
if (UpdateTheGui)
{
UpdateTheGui = false;
UpdateTheGuiNow();
}
}
}
private void UpdateTheGuiNow()
{
if (label1.InvokeRequired)
{
label1.Invoke(new UpdateGUI(UpdateTheGuiNow));
return;
}
label1.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
label2.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
label3.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
}
private void btnInvoke_Click(object sender, EventArgs e)
{
UpdateTheGui = true;
}
8 Réponses :
Ceci est le modèle standard pour utiliser Êtes-vous sûr que votre problème n'est pas causé par un autre code de votre application qui n'est pas inclus dans votre question? P> invoquer code> à mises à jour Marshall au fil de l'interface utilisateur. p>
Pas tout à fait sûr, mais voyez la modification à la question et aussi le commentaire à la réponse de Hans. C'est un problème très inhabituel.
Je ne pense pas que ce soit lié. J'attendais peut-être que le collecteur des ordures élimine le (s) objet (s) nouvellement attribué (s) Invoke (). P>
Appeler gc.collect () code> arrêtera les poignées de l'augmentation. Fait intéressant, si
gc.collect () code> est ajouté après l'exécution du programme pendant un moment, pendant un point de rupture, il ne réduira pas les poignées à un état initial, mais les empêchera simplement de s'accumuler.
La méthode Control.Invoke () ne consomme aucune poignée. Cependant, ce code est clairement appelé d'un fil. Un thread fait em> consommer des poignées 5 d'entre eux. P>
La classe de thread ne dispose pas d'une méthode (), même si elle devrait en avoir une. C'était probablement par la conception, il serait très difficile d'appeler de manière fiable, incroyablement afin de fileter de threadpool. Les 5 poignées qu'un fil nécessitent sont libérés par le finaliseur. Votre programme nécessitera de plus en plus de manipulations si le finaliseur ne fonctionne jamais. P>
Ne pas faire fonctionner le finaliseur est assez inhabituel. Vous devriez avoir un programme qui commence beaucoup de threads mais n'alloue pas beaucoup de mémoire. Cela a tendance à ne se produire que dans des tests statiques. Vous pouvez diagnostiquer cette condition avec perfmon.exe, utiliser les compteurs de performance de la mémoire .NET et vérifier si les collections de Gen # 0 sont en cours. P>
Si cela se produit dans un programme de production, vous devrez appeler GC.Collect () vous-même pour éviter une fuite de poignée en fuite. P>
J'ai utilisé le modèle décrit pour mettre à jour des composants de l'interface utilisateur dans le passé, sans le problème d'augmentation de la poignée, mais dans le projet en cours, il s'agit certainement de quelque chose à voir avec cet appel thread-to-ui. Si je commente la partie qui vérifie et appelle le délégué, et que checkforillegalcrossthreadcalls = false; code> puis les poignées arrêtent d'augmenter, bien que je ne veux pas le laisser dans un tel état. Je vais mettre à jour la question avec cette information.
Eh bien, cela défie une explication facile. Donnez-nous une idée de ce que le reste du code fait et à quel énoncé spécifique vous voyez le nombre de personnes augmente.
Ajout d'un échantillon qui montre le problème plus en détail. Un bouton du formulaire déclenche la mise à jour.
Il y a une autre discussion utile de ce problème ici: Stackoverflow.com/questions/1603123/...
Je vois effectivement le même problème que Jyelton. J'ai le même appel à partir d'un fil pour mettre à jour l'interface utilisateur. P>
Dès que la ligne somecontrol.invoke (nouveau délégadiuupdate (uiUpdate)); code> est appelé, la poignée augmente d'une. Il y a certainement une fuite de quelque sorte sur l'invoke, mais je n'ai aucune idée de ce qui le causait. Cela a été vérifié sur plusieurs systèmes. P>
J'ai vu la même chose dans mon code. Je l'ai réparé en remplaçant Doron. P> invoke code> avec
begininvoke code>. La fuite de la poignée s'est éloignée. P>
J'ai eu le même problème avec Création d'une poignée à chaque appel. p> Les incréments de la poignée car on invoque est synchrone et efficacement la poignée a été laissée suspendue. Soit une poignée d'attente doit être utilisée pour traiter le résultat ou la méthode asynchrone de begininvoke comme indiqué ci-dessous. P> this.BeginInvoke(new DelegateClockUpdate(ChangeClock), sender, e);
Merci Mec! Votre réponse est Sooo Cool, qui a sauvé mon application de la top-amie et de 3 jours d'enquêtes. Vous savez probablement le profilage de Somw NinJustsu ... vous êtes un vrai coquin!
appel AYNC avec la poignée explicite finaliser. Exapmle: voir http : //msdn.microsoft.com/en-us/library/system.iaysynccresult.asyncwaithandle.aspx Note: P> Lorsque vous utilisez la méthode de BeginInvoke d'un délégué pour appeler une méthode asynchrone et obtenez une poignée d'attente de l'iAsyncresulte résultant, nous vous recommandons de fermer la poignée d'attente dès que vous avez fini de l'utiliser, en appelant le waihandle.flose méthode. Si vous libérez simplement toutes les références à la poignée d'attente, les ressources système sont libérées lorsque la collecte des ordures recouvre la poignée d'attente, mais la collecte des ordures fonctionne plus efficacement lorsque des objets jetables sont explicitement fermés ou disposés. Pour plus d'informations, voir la propriété AsyncResult.Asyncwaithandle. P>
blockQuote> p>
Voici une méthode d'extension qui fonctionne de la même manière à l'appel d'invocation normal, mais nettoyera la poignée après: Vous pouvez ensuite l'appeler très similaire à une invocation normale: P > myForm.InvokeAndClose((MethodInvoker)delegate
{
someControl.Text = "New Value";
});
J'ai le même problème ici, avec exactement le même appel sur une minuterie. Merci d'avoir mentionné CheckforillegalcrossthreadCalls parce que je n'en ai jamais entendu parler auparavant.