Sto facendo una patch per risolvere un problema della barra di avanzamento in un'applicazione che è un po 'incasinato. L'annullamento sulla barra di avanzamento utilizzato per fare un Thread.Abort
sul thread facendo il lavoro pesante. L'ho modificato per innalzare un flag di annullamento che posso verificare in un punto strategico nel thread.Come evitare di morire di fame il filo principale?
La maggior parte delle volte funziona, ma una volta tanto la cancellazione non funziona affatto. Suppongo di poter fare uno Application.DoEvents
prima di guardare lo stato della bandiera (non vi è alcun rischio di rientro), ma vorrei un'opzione più "pulita".
Apprezzerei se qualcuno potesse fornirmi informazioni per capire cosa sta succedendo esattamente e come questa roba funziona dietro la scena. Mi piacerebbe sapere come affrontare questo problema senza usare lo BackgroundWorker
(come si farebbe con .net 1.1) ma vorrei anche sapere se lo BackgroundWorker
risolve questo tipo di problemi e come lo fa.
Modifica: Sto prendendo nota dei tuoi suggerimenti e proverò domani e riferirò. All'inizio ho usato un bool volatile, penso di averlo aggiornato ad una proprietà automatica e ho dimenticato la volatilità. È possibile che il thread di lavoro continui a cercare il valore memorizzato nella cache ancora e ancora? Non vedo come potrei avere un punto morto. Il lavoratore per controllare la bandiera da quando sono riuscito a rompere lì inserendo un punto di interruzione al volo. Io cerco sempre lo stesso insieme di dati e il più delle volte cancella perfettamente. L'unica cosa che cambia tra i test è il momento in cui premo Annulla. Finora, ho testato solo in debug, avviato da VS.
Modifica 2: il mio problema non è correlato alla mia bandiera o a qualcosa che ho aggiunto. È più un problema di WinForm. Il programma arriva a chiamare uno ShowDialog
(e c'è già un altro ShowDialog bloccato). Non riesco a trascinare il modulo e non si aggiorna da solo. Il pulsante Annulla non funziona nemmeno. Ecco lo stack delle chiamate quando metto in pausa tutto.
[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]
Edit 3: Se passo null
al ShowDialog funziona benissimo (l'interfaccia utente non gela, il funzionamento del pulsante cancella, cancella bene). Non capisco davvero la magia dietro a tutto questo.
C'è qualche vantaggio nell'usare 'ManuelResetEvent' su un flag' volatile' in quella situazione? Oltre alla possibilità di bloccare se necessario (cosa che non faccio), non ne vedo. –
Lo uso perché è progettato specificamente per segnalare uno o più thread e non richiede molta attenzione per implementare correttamente. Nel complesso è probabilmente "più pesante" di una bandiera volatile. Entrambi funzioneranno, preferisco uno rispetto all'altro :-) –
Ok. Il mio problema è chiaramente un deadlock non correlato alla mia modifica. I deadlock quando si chiama 'ShowDialog' su un clic del pulsante già in una finestra di dialogo. Presumo che la chiamata multipla a ShowDialog sia negativa. Modifica: prevediamo di bloccare quelli ShowDialog ma siamo comunque in grado di elaborare eventi come il pulsante Annulla su di esso. –