Estoy haciendo un parche para resolver un problema de barra de progreso en una aplicación que está un poco desordenada. La cancelación en la barra de progreso solía hacer un Thread.Abort
en el hilo haciendo el trabajo pesado. Cambié eso a levantar una bandera de cancelación que puedo verificar en el lugar estratégico en el hilo.¿Cómo evitar pasar hambre con el hilo principal?
La mayoría de las veces funciona bien, pero de vez en cuando la cancelación no funciona en absoluto. Supongo que podría hacer un Application.DoEvents
antes de mirar el estado de la bandera (no hay riesgo de reingreso) pero me gustaría una opción más "limpia".
Agradecería que alguien me pudiera proporcionar información para comprender qué está sucediendo exactamente y cómo funciona esto detrás de la escena. Me gustaría saber cómo tratar este problema sin utilizar el BackgroundWorker
(como lo haría en .net 1.1) pero también me gustaría saber si el BackgroundWorker
resuelve ese tipo de problemas y cómo lo hace.
Editar: Estoy tomando notas de sus sugerencias e intentaré algo mañana e informaré. Al principio, utilicé un bool volátil porque creo que lo actualicé en una propiedad automática y me olvidé de lo volátil. ¿Podría el hilo del trabajador seguir buscando el valor en caché una y otra vez? No veo cómo podría tener un deathlock. El trabajador para verificar la bandera desde que logré romper allí colocando un punto de quiebre sobre la marcha. Siempre pruebo con el mismo conjunto de datos y la mayoría de las veces cancela muy bien. Lo único que cambia entre las pruebas es el momento en que presiono cancelar. Hasta ahora, solo probé en depuración, comencé desde VS.
Editar 2: Resulta que mi problema no está relacionado con mi bandera o cualquier cosa que agregué. Es más un problema de WinForm. El programa puede llamar al ShowDialog
(y ya hay otro ShowDialog bloqueado). No puedo arrastrar el formulario y no se actualiza por sí mismo. El botón de cancelar no funciona. Aquí está la pila de llamadas cuando pause todo.
[Code externe] Mrnf.Son.Commun.dll!Mrnf.Son.Commun.Messages.BarreProgressionBase.ShowDialog(System.Windows.Forms.IWin32Window fenetre = {Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm}) Ligne 274 + 0xb octets C# Mrnf.Son.Commun.dll!Mrnf.Son.Commun.Controleurs.Utils.AttendreFinTraitement(System.Windows.Forms.Form parent = {Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm}, Mrnf.Son.Commun.Messages.BarreProgressionBase progressionBase = {Mrnf.Son.Commun.Messages.BarreProgressionMessage}, System.Threading.Thread thread = {System.Threading.Thread}) Ligne 302 + 0xd octets C# Mrnf.Son.Affaires.dll!Mrnf.Son.Affaires.Persisteurs.Echanges.LecteurDBFGeneriqueCollection.Importer(System.Windows.Forms.Form parent = {Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm}) Ligne 95 + 0x1d octets C# Mrnf.Son.Affaires.dll!Mrnf.Son.Affaires.Persisteurs.Echanges.PersisteurModeleEchanges.Importer(Mrnf.Son.Affaires.Entites.Echanges.ModeleEchanges unModele = {Mrnf.Son.Presentation.Windows.Controleurs.Echanges.ModeleEchanges.ModeleEchangesGenerique}, System.Windows.Forms.Form formParent = {Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm}) Ligne 1880 + 0xd octets C# Mrnf.Son.Affaires.dll!Mrnf.Son.Affaires.Entites.Echanges.ModeleEchanges.Importer(System.Windows.Forms.Form formParent = {Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm}) Ligne 875 + 0x18 octets C# Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm.EffectuerImport(Mrnf.Son.Affaires.Entites.Echanges.IModeleEchanges modele = {Mrnf.Son.Presentation.Windows.Controleurs.Echanges.ModeleEchanges.ModeleEchangesGenerique}) Ligne 1429 + 0xc octets C# Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm._terminerBtn_Click(object sender = {Text = Impossible d'évaluer l'expression, car un frame natif se trouve en haut de la pile des appels.}, System.EventArgs e = {System.EventArgs}) Ligne 1334 + 0x1d octets C# [Code externe] Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.UI.Echanges.AssistantForm.WndProc(ref System.Windows.Forms.Message m = {System.Windows.Forms.Message}) Ligne 1133 + 0xb octets C# [Code externe] Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.Controleurs.Sondages.ActionsSondages.OnImporterSysExt() Ligne 1362 + 0x1f octets C# Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.UI.Sondages.UEExploitationVue._mniImporterSysExt_Click(object sender = {System.Windows.Forms.ToolStripMenuItem}, System.EventArgs e = {System.EventArgs}) Ligne 820 + 0x12 octets C# [Code externe] Mrnf.Son.Presentation.Windows.exe!Mrnf.Son.Presentation.Windows.Program.Main() Ligne 148 + 0x8 octets C# [Code externe]
Datos 3: Si paso null
a la ShowDialog funciona bien (la interfaz de usuario no se congela, el funcionamiento del botón cancelar, se cancela fina). Realmente no entiendo la magia detrás de todo esto.
¿Hay alguna ventaja de usar 'ManuelResetEvent' sobre una bandera' volátil' en esa situación? Además de la posibilidad de bloquear si es necesario (que no), no veo ninguno. –
Lo uso porque está específicamente diseñado para señalar uno o más hilos y no toma mucha consideración para implementarlo correctamente. En general, es probablemente "más pesado" que una bandera volátil. Ambos funcionarán. Prefiero uno sobre el otro :-) –
Ok. Mi problema es claramente un punto muerto no relacionado con mi modificación. Me interrumpe al llamar 'ShowDialog' en un clic de botón ya en un diálogo. Supongo que la llamada múltiple a ShowDialog es mala. Editar: esperamos bloquear en esos ShowDialog, pero aún así poder procesar eventos como el botón cancelar en él. –