[C#] Multi threaded app. -> A first chance exception

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
In mijn applicatie start ik een thread op met:
code:
1
ThreadPool.QueueUserWorkItem(new WaitCallback(this.WorkDevider), obj);


Deze thread start twee andere threads:
code:
1
2
3
4
5
this.t1 = new Thread(new ThreadStart(this.ProcessData1));
this.t1.Start();
this.t2 = new Thread(new ThreadStart(this.ProcessData2));
this.t2.Start();
this.WorkDone();


WorkDone() blijft doorlopen met een loop die test of de twee threads klaar zijn (een teller) om daarna het uitgevoerde werk samen te voegen.

Dit alles zit verpakt in een class waar ik Form variable is opgenomen. Deze krijgt de referentie van de form mee die de thread opstart. De applicatie kent twee forms dus de applicatie draait met maximaal 4 threads. Elke form houdt zelf bij wat de stand van zaken is.

Als de user het programma sluit moeten de thread ook stoppen. Dit gebeurt middels een delegate die uitgevoerd aangeroepen wordt door de thread.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void ProcessData1()
        {
            try
            {
                //do work
                this.DelForm.Invoke(new GetExit(this.getexit), 1);
                this.Blend1();
                if ((bool)this.DelForm.Invoke(new GetExit(this.getexit), 2) == true)
                {
                    this.DelForm.Invoke(new GetExit(this.getexit), 0);
                    return;
                }
                //end work
                ((Form)this.DelForm).Invoke(new UpdateWorkCount(this.AddWorkcount), null);
                this.DelForm.Invoke(new GetExit(this.getexit), 0);
            }
            catch
            {
                return;
            }
        }

Delform is dus de afgeleide van de Form die de thread heeft opgestart.
Bij een 1 wordt de teller in de Form (die de thread heeft opgestart) met 1 opgehoogd. Bij 2 wordt alleen de status uitgelezen en bij 0 wordt de teller in de Form met één verlaagd.

Het probleem is nu dat mijn applicatie een "A first chance exception of type 'System.ObjectDisposedException' occurred in System.Windows.Forms.dll" geeft. (Debugger).

Dus lijkt het alsof de Form eerder gesloten wordt dan dat de threads gecanceld zijn en de teller in de Form(s) weer op 0 staat. Eigenlijk zou pas dan de Form mogen sluiten.

De code om de forms mee af te sluiten:
Form1 + 2:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
private void closeF2()
        {
            this.timer1.Enabled = false;
            try
            {
                if (this.f2 != null)
                {
                    if (f2.Visible == true)
                    {
                        if (f2.CancloseF2 != 0)
                        {
                            f2.closeF2fromF1();
                            Int32 i = 0;
                            while (f2.CancloseF2 != 0)
                            {
                                i++;
                                if (i == 100)
                                {
                                    break;
                                }
                            }
                        }
                    }
                    f2.Close();
                }
                this.Close();
            }
            catch
            {
            }
        }

//Code in Form2

public void closeF2fromF1()
        {
            if (this.MultiP != null)
            {
                this.timer1.Enabled = false;
                this.MultiP.exitOverride = true;
                Int32 i = 0;
                while (this.CancloseF2 != 1)
                {
                    i++;
                    if (i == 100)
                    {
                        break;
                    }
                }
            }
        }


Als ik de break uit de loops haal hangt de applicatie. Blijkbaar bereiken de tellers geen 0. Bij het afsluiten treedt er een exceptie op in ProcessData1() (origine van de exceptie is de DelForm.Invoke). Blijkbaar mag dat niet meer op dat tijdstip. exitOverride geeft trouwend het startschot aan de thread om te stoppen (if ((bool)this.DelForm.Invoke(new GetExit(this.getexit), 2) == true)).

De threads stoppen wel (de applicatie sluit dus af maar dat alleen door het afvangen van de excepties en de returns). Maar toch heb ik het gevoel dat ik niet op een juist spoor zit of dat het beter/mooier kan.

Wie kan er iets over vertellen / een duw in de juiste richting geven. Om de applicatie zonder excepties te kunnen afsluiten.

Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op zaterdag 28 maart 2009 @ 16:22:
Het probleem is nu dat mijn applicatie een "A first chance exception of type 'System.ObjectDisposedException' occurred in System.Windows.Forms.dll" geeft. (Debugger).

Dus lijkt het alsof de Form eerder gesloten wordt dan dat de threads gecanceld zijn en de teller in de Form(s) weer op 0 staat. Eigenlijk zou pas dan de Form mogen sluiten.
Deze aanname lijkt me correct. De ObjectDisposedException geeft aan dat het object waar je iets mee wilt doen al gedisposed is en volgens mij kan dat in het voorbeeld wat je geeft alleen je form zijn.
Verwijderd schreef op zaterdag 28 maart 2009 @ 16:22:
...

WorkDone() blijft doorlopen met een loop die test of de twee threads klaar zijn (een teller) om daarna het uitgevoerde werk samen te voegen.

...

Bij een 1 wordt de teller in de Form (die de thread heeft opgestart) met 1 opgehoogd. Bij 2 wordt alleen de status uitgelezen en bij 0 wordt de teller in de Form met één verlaagd.

...

Wie kan er iets over vertellen / een duw in de juiste richting geven. Om de applicatie zonder excepties te kunnen afsluiten.
Imho zou je nog eens goed over je ontwerp na moeten denken want met de huidige informatie lijkt het alsof je een lelijke oplossing voor een eenvoudig probleem hebt gekozen. Misschien dat je iets meer informatie kunt geven over wat je precies wilt bereiken? Want het probleem oplossen door de oorzaak te verwijderen met een mooier ontwerp lijkt me de allermooiste oplossing :P

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Verwijderd schreef op zaterdag 28 maart 2009 @ 17:58:
[...]
Imho zou je nog eens goed over je ontwerp na moeten denken want met de huidige informatie lijkt het alsof je een lelijke oplossing voor een eenvoudig probleem hebt gekozen. Misschien dat je iets meer informatie kunt geven over wat je precies wilt bereiken? Want het probleem oplossen door de oorzaak te verwijderen met een mooier ontwerp lijkt me de allermooiste oplossing :P
Het gaat om een screensaver die foto's laat zien voor maximaal twee schermen. De transitie van de ene foto naar de andere foto moet geleidelijk verlopen. Geen problemen tot hier.

Maar bij user input moet de screensaver afsluiten. En daar gaat het dus blijkbaar fout.

De technische flow is als volgt:

Applicatie start-> laad plaatje -> start timer -> start class met oude foto + nieuwe foto -> start thread main (blijft actief) -> start twee andere threads -> voeren bewerkingen uit -> koppelen terug naar thread main -> thread main bepaald of het het uiteindelijk resultaat is bereikt * -> zo niet plaatje terugkoppelen naar form -> twee threads opnieuw opstarten -> bij eindresultaat zet thread main de timer aan -> thread main sluit af.

* voorbeeld van een tussenstap
http://www.pwiv.nl/GOT/Photo Blender 3.png

Acties:
  • 0 Henk 'm!

Verwijderd

Je thread-synchronisatie is bijzonder te noemen (met de tellertjes en polling dmv while loops). Wat je volgens mij wilt is conceptueel je thread(s) aan je form koppelen. Wanneer je form afgesloten moet worden synchroniseer je met je worker-thread(s) (door bv een Thread.Join() of een ander synchronisatie mechanisme) om te bepalen of je worker thread(s) al klaar is / zijn. Zie de MSDN voor meer informatie over synchronisatie mechanismen voor threads. Dan weet je precies wanneer je threads klaar zijn en wanneer je je form zou willen closen.

Hoe sluit je je applicatie trouwens af bij user input? Want wanneer je iets in de trant van System.Exit doet ofzo dan worden je (background)threads gewoon keihard gekilled en je forms gewoon gedisposed en zul je altijd vage meldingen houden. Je zult dus nog iets ergens met een Exit event moeten doen om een nette shutdown te krijgen.

My guess op dit moment is dat je tellertje nooit op 0 gezet wordt omdat je UI thread (de thread waar de Invoke om je teller op 0 te zetten op uitgevoerd zou moeten worden) heel hard aan het werk is met belangrijke dingen. Namelijk checken of je teller op 0 staat.

Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Die first chance exceptions zie je alleen in je output toch? En die zorgen er niet voor dat je programma stopt/crashed? Lees ook (eerste google hit)

http://blogs.msdn.com/dav...ve/2005/07/12/438061.aspx
First chance exception messages most often do not mean there is a problem in the code. For applications / components which handle exceptions gracefully, first chance exception messages let the developer know that an exceptional situation was encountered and was handled.

For code without exception handling, the debugger will receive a second chance exception notification and will stop with a unhandled exception.
First chance exceptions zijn over het algemeen niets om je zorgen over te maken en gebeuren vaak in het achterliggende framework in debug-mode bij het gebruik van meerdere threads (heeft iets met de debugger te maken die de threads in de gaten houd ofzo)

[ Voor 16% gewijzigd door roy-t op 30-03-2009 11:24 ]

~ Mijn prog blog!