C# Vermoedelijk threading probleem

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 16-06 15:55

SideShow

Administrator

Topicstarter
Hallo

Ik ben dus bezig met eenvoudige oefeningen en heb enkele vragen omtrent dit test wip project: *knip*

Het is een system tray tool die eenvoudig, percentage-gewijs, aangeeft hoeveel je downloadsnelheid bedraagt. (Let wel, de maximale downloadsnelheid is momenteel hard coded, evenals de selectie van de netwerk adapter)

Het compileert en loopt prima, alleen durft het zo heel af en toe eens vast te lopen; het crasht niet maar het reageert en update niet meer echt. Ik vermoed dat het te maken heeft met threading (deadlock?)

Het updaten van de form lukte al helemaal niet, en staat daarom in commentaar.
De bool CheckForIllegalCrossThreadCalls heb ik geprobeerd maar uiteindelijk achterwege gelaten omdat dit een vuile truk blijkt te zijn; én het lost mijn probleem niet op.

Ik vraag niet van mijn probleem op te lossen, maar ik wil gewoon zeker zijn dat de reden inderdaad met threads te maken heeft, en ik mij best daarin eens ga verdiepen. Daar hangen dan wellicht ook events en delegates aan vast om dit tot een goed einde te brengen?

Dus als ik het momenteel goed zie, is de timer een andere thread, en probeert dus in een andere thread controls aan te passen met behulp van mijn refresh method?

Nog enkele punten:

- is dit wel een goede manier van werken? Al die statics enzo?
- ik heb geen gemiddelde functie gevonden en heb dus maar een eigen mini class gebruikt
- ik vermoed dat er een memory leak in zit. (Geheugen gaat iedere seconde met 4K omhoog) Ik dacht eerst aan de refresh functie die telkens een nieuw bitmap object aanmaakt, maar de geheugenlocatie van het vorige object zou toch telkens vrijgegeven moeten worden, gezien niks nog refereert. Sowieso dacht ik als een functie ten einde is, alle variabelen worden vrijgegeven?

[ Voor 1% gewijzigd door NMe op 06-05-2011 01:03 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Dit is dus niet de bedoeling. We gaan niet jouw complete project downloaden en voor je debuggen; debuggen mag jij doen. Vervolgens kom je vast bepaalde code tegen die relevant is voor je probleem en enkel die relevante code zou je hier in het topic kunnen posten. "Dit is mijn code" + downloadlink beginnen we in elk geval niet aan. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 17-09 10:59

Ventieldopje

I'm not your pal, mate!

- is dit wel een goede manier van werken? Al die statics enzo?
Als je een programma hebt dat alleen een tray icon en dus geen main form heeft wel ;)

- ik vermoed dat er een memory leak in zit.
Die lijkt me inderdaad te zitten bij het refreshen, bitmap clone ;)

Wat betreft de threads moet je voor het updaten checken of je moet invoken (uitvoeren op een andere thread) met Control.InvokeRequired (frmToolWindow.InvokeRequired in jouw geval). Als die true geeft zit je in een andere thread te werken en moet je invoken met frmToolWindow.BeginInvoke(), geeft hij false zit je in de goede thread (die van frmToolWindow) en kun je rustig het window updaten ;)

Denk dat je er daar mee wel uit komt ;)

edit: eens met NMe ;)

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 16-06 15:55

SideShow

Administrator

Topicstarter
@NMe, ik begrijp het, maar er valt niks te debuggen (edit: toch niet letterlijk), ik dacht dat men op die manier makkelijker zou kunnen inpikken


@ventiel: bedankt, dit is duidelijk voor de form. Het tray icon, daar ben ik nog niet uit. Dit geeft geen compiler of runtime problemen, en ik vind niet direct iets terug van invoke op dit object, maar toch hangt mn applicatie af en toe, na 5 minuten, kan ook na een uur zijn ...

[ Voor 83% gewijzigd door SideShow op 06-05-2011 01:37 ]


Acties:
  • 0 Henk 'm!

  • Radiant
  • Registratie: Juli 2003
  • Niet online

Radiant

Certified MS Bob Administrator

Run je programma in een debugsessie, wacht tot het gebeurt, zet je programma op pauze en kijk naar de staat van je programma? Als je threads gebruikt, wissel er tussen en kijk wat ze aan het doen zijn, of kijk wat voor condities ervoor zorgen dat je icon niet meer geüpdatet wordt.

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 03:43
Ik weet niet hoe intensief de operatie is die je in je timer uitvoert, maar als dat niet zo heel veel doet zou je misschien ook een andere timer kunnen gebruiken: MSDN: Timer Class (System.Windows.Forms). Dan heb je geen gedoe met threads meer.

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 17-09 10:59

Ventieldopje

I'm not your pal, mate!

Het timer object roept in dit geval gewoon een callback aan, timer en callback lopen in een andere thread en dat is ook goed. Wat is er mis met gewoon even simpel invoken, dan is je probleem opgelost?

Alle objecten die afgeleid zijn van Control hebben een InvokeRequired bool en BeginInvoke method, ik gokte dat frmToolWindow dat ook wel zou hebben, zou je even mee moeten spelen, heb hier geen VisualStudio bij de hand ;)

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

  • Chip.
  • Registratie: Mei 2006
  • Niet online
Commentaar op moderatie kan in: Feedback op moderatie binnen de Devschuur

[ Voor 92% gewijzigd door Woy op 06-05-2011 13:35 ]


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

*snip* Discussie over moderatie kan in: Feedback op moderatie binnen de Devschuur

[ Voor 88% gewijzigd door Woy op 06-05-2011 15:14 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 17-09 10:59

Ventieldopje

I'm not your pal, mate!

*snip* Discussie over moderatie kan in: Feedback op moderatie binnen de Devschuur

[ Voor 99% gewijzigd door Woy op 06-05-2011 15:15 ]

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 16-06 15:55

SideShow

Administrator

Topicstarter
Hallo

Ik heb de reden gevonden waarom mn applicatie soms vastloopt:
trayIcon.Icon = Icon.FromHandle(bmp.GetHicon());

Deze heeft een hele kleine kans dat het vast loopt, met de melding "GDI+ Generic error".
Het heeft als gevolg dat mijn hele timer event niet meer wil werken, zelfs al zet ik het in een try/catch
Hier een voorbeeld van een gelijkaardige functie (ik heb de timer interval op 10 milliseconden gezet, op deze manier gebeurt het bijna zeker binnen de minuut)


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void tik(object sender, EventArgs e)
{
    Bitmap b = new Bitmap(16, 16);
    Graphics g = Graphics.FromImage(b);

    g.DrawString("A", new Font("Tahoma", 8), new SolidBrush(Color.White), 4, 4);

    try
    {
        trayIcon.Icon = Icon.FromHandle(b.GetHicon());
    }
    catch (Exception ex)
    {
        Console.Beep();
    }
    finally
    {
        b.Dispose();
        g.Dispose();
        GC.Collect();
    }
}


Iemand hier bekend mee?


*edit: ondertussen de oplossing gevonden voor zowel de crash als de memory leak:

[DllImport("user32.dll", EntryPoint = "DestroyIcon")]
static extern int DestroyIcon(IntPtr hIcon);

vervolgens mijn tray icon updaten als volgt:

IntPtr handle = bmp.GetHicon();
trayIcon.Icon = Icon.FromHandle(handle);
DestroyIcon(handle);

Iets heel lelijk en ik snap het helemaal niet. Wat zijn handle's eigenlijk, en waarom moet ik ze destroyen anders crasht mijn app? C# leren ... voor elke nieuw antwoord ontstaan er 10 nieuwe vragen...

[ Voor 23% gewijzigd door SideShow op 09-05-2011 20:14 ]


Acties:
  • 0 Henk 'm!

  • ThaStealth
  • Registratie: Oktober 2004
  • Laatst online: 11-09 10:19
Gebruik de Stopwatch (in System.Diagnostics) eens en meet eens hoelang deze functie duurt.
Bitmap manipulaties kunnen nogal eens zwaar zijn (en dus lang duren) (weet niet of het in dit geval met het kleine plaatje ook zo is). Maar als je boven de 10 ms uitkomt is het event al nogmaals gefired terwijl de functie nog bezig is.

Mess with the best, die like the rest


Acties:
  • 0 Henk 'm!

  • ThaStealth
  • Registratie: Oktober 2004
  • Laatst online: 11-09 10:19
Een handle is een pointer (=referentie) naar een stuk win32 code (unmanged => geen .NET code). Het .NET framework weet niet wanneer je klaar bent met de pointer en hij het dus kan opschonen (normaal weet hij dit wel omdat hij dit kan bijhouden).

Je moet dus tegen .NET vertellen dat je klaar bent met de pointer en dat hij het mag opschonen voor jouw

Mess with the best, die like the rest


Acties:
  • 0 Henk 'm!

  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 16-06 15:55

SideShow

Administrator

Topicstarter
Dankje

Zo zie je maar, een "simpele" C# applicatie maken als testje, is blijkbaar een illusie. Dit lijkt me toch geen basis meer; ben ik althans nog nergens tegengekomen in mijn "C# for beginners" kind of boeken

Acties:
  • 0 Henk 'm!

  • epic007
  • Registratie: Februari 2004
  • Laatst online: 25-08 11:27
In C# ruimt de 'garbage collector' alle niet gebruikte geheugen voor je op. Je kan dus onbeperkt 'new ...' aanroepen zonder dat je zelf bij moet houden wat je hebt aangemaakt. (in je voorbeeld maak je 100x per seconde een bitmap aan van 16x16 pixels).

'Vroeger' ( :P ) moest je als programmeur zelf je geheugenbeheer doen (zie C en C++) voor elke 'new ..' moet ergens een 'delete ..' in de code staan om het geheugen weer vrij te geven.

Zo werkt het ook met Win32 code. Voor elk window, icon, bitmap e.d. wat aangemaakt wordt bestaat een Create.. functie maar ook een Destroy.. functie.

Het .NET framework heeft voor de meeste van dit soort dingen wel eigen classes die met de garbage collector werken, maar soms (zo als je voorbeeld met de trayicon) raak je de native win32 api en moet je het alsnog zelf doen.

[ Voor 4% gewijzigd door epic007 op 10-05-2011 10:42 ]


Acties:
  • 0 Henk 'm!

  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 16-06 15:55

SideShow

Administrator

Topicstarter
Dus nog even voor de zekerheid ... een "handle" is dus altijd "unmanaged" ?
Omdat b.GetHicon mij toch native c# code lijkt ?
Uiteindelijk snap ik nog steeds niet dat een memory leak verantwoordelijk kan zijn voor het hangen van deze event.

Ik blijk trouwens niet de enige die problemen heeft met getHicon.
Voorbeeld: http://connect.microsoft....-drawing-bitmap-gethicon#

Voor alle duidelijkheid, momenteel is mn applicatie in orde, hangt niet meer en het geheugenlek is ook verdwenen, dankzij de DestroyIcon
Pagina: 1