Toon posts:

[C++] plugins en asynchronous calls *

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb een programma. Dit programma gebruikt DLLs. De DLLs kunnen aan het programma vragen om een URL te downloaden. Deze wordt als return van de functie meegegeven.

maw:
(in plugin) -> DownloadURL(...) -> je krijgt resultaat.

Nu is het zo dat als ik een URL download, dat mijn programma volledig locked. Akkoord, dat is normaal en ligt aan mijn implementatie van DownloadURL.

Nu zou ik natuurlijk (omdat het aantal plugins kan stijgen) een soort van "Download-pool" willen maken zodat de plugins allemaal tegelijk kunnen vragen aan mijn main programma om een URL te downloaden.

Probleem daarbij is dan dat ik moet gaan werken met threads. Niet het werken met die threads is het probleem, maar eerder de logica erachter.

Laat me eventjes proberen duidelijker te zijn.


Op dit moment 'locked' de plugin en het hoofdprogramma totdat de URL is gedownload.
Als ik nu met threads zal gaan werken zou ik eigenlijk OOK als returnwaarde van die functie de gedownloadde URL willen meegeven.

Dit kan ik gerust doen door bvb een ::Sleep(xx) te doen.
[vraag1: locked Sleep() ook mijn andere threads, of enkel de GUI/main programma?]

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string DownloadURL( string url )
{
  if ( url.empty() )
    return "";

  string result;

  bool ThreadHasStoppedLeeching( false );
  DownloadThread *thread = new DownloadThread( url, result, ThreadHasStoppedLeeching );

  thread->Run();

  while ( !ThreadHasStoppedLeeching )
    ::Sleep(100);

  return result;
}


Het beste natuurlijk wat ik kan doen is met een "event system" gaan werken...
Dus gewoon een thread afvuren, en dan wachten op de event. Op die manier moet ik ook niet "sleep"-en.

Maar dan zit ik wel met het probleem dat ik niet meer het resultaat kan returnen als uitkomst van de DownloadURL-functie...

[vraag2: Heeft er iemand enig idee hoe ik dit probleem kan oplossen? Op dit moment bestaat de mogelijkheid nog om de API van de plugins te wijzigen.]

Moest ik ergens onduidelijk geweest zijn, gelieve dan meer info te vragen ;)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 03 juli 2004 @ 01:39:
[vraag1: locked Sleep() ook mijn andere threads, of enkel de GUI/main programma?]
Sorry hoor, maar dit is toch wel zo enorm RTFM dat ik 'm niet eens ga beantwoorden. Sla de MSDN maar eens open zou ik zeggen :/
[vraag2: Heeft er iemand enig idee hoe ik dit probleem kan oplossen? Op dit moment bestaat de mogelijkheid nog om de API van de plugins te wijzigen.]
Ik vraag me af wat het verschil is tussen geen threads gebruiken en het stukje code wat je zojuist gaf. Ik neem aan dat alle plugins in dezelfde thread draaien, anders had je het oorspronkelijke blocking probleem sowieso al niet. Hoe denk je dan dat je stukje code je blocking probleem gaat oplossen dan? De functie blockt nog net zo hard, ook al start hij onder water een andere thread waar hij vervolgens op gaat wachten. Als hij er toch op wacht hoeft ie natuurlijk ook niet een andere thread op te starten, dan kan het downloaden net zo goed in de huidige thread plaats vinden.

Mijn inziens heb je 2 oplossingen: geef elke plugin z'n eigen thread, of ga idd met een event systeem werken. Elke plugin in z'n eigen thread lijkt me denk ik niet echt gewenst, daar moet je gewoon teveel voor regelen. Een event systeem lijkt me het handigst, je zegt gewoon dat er iets gedownload moet worden, en zodra dat gedaan is wordt de betreffende plugin ervan op de hoogte gebracht. Op deze manier kun je nog alle kanten op, als een plugin echt een eigen thread wil kan ie dat altijd zelf nog regelen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Ik gebruik een thread omdat ik in de thread nog een "progressbar" teken.
En als mijn programma een erase-background-event ontvangt wordt dit hertekend (wat niet het geval zou zijn moest ik volledig lineair werken, nu worden alle events elke 100ms gechecked).

Wat bedoel je juist met elke plugin in zijn eigen thread?
Op dit moment scan ik alle plugins en laad ik deze via ::LoadLibrary...

**edit**
Ik dacht dat als je een loadlibrary deed, dat je dan de plugin laadde in een aparte thread?
**edit**

Als ik het goed begrijp zou jij voorstellen eerst een "plugin-thread" te maken, en hierin de loadlibrary doen?
Wat voor moeilijkheden zie je hierbij optreden?

**edit**
Maar voor zover ik weet haalt dat niets uit, daar de DownloadURL functie in het hoofdprogramma zit... Dus in de mainthread... Dan draaien de plugins misschien wel in threads, maar ze vragen allemaal aan de mainthread dezelfde functie op? Of zit ik verkeerd te denken?
**edit**

[ Voor 31% gewijzigd door Verwijderd op 03-07-2004 02:27 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 03 juli 2004 @ 02:09:
**edit**
Ik dacht dat als je een loadlibrary deed, dat je dan de plugin laadde in een aparte thread?
**edit**
Grappige aanname, ik vraag me af waar je dat vandaan haalt :)
Dat is dus geenzins zo, LoadLibrary roept gewoon de entry point van de dll aan (DllMain) in de huidige thread, en returnt daarna weer naar de caller.
Als ik het goed begrijp zou jij voorstellen eerst een "plugin-thread" te maken, en hierin de loadlibrary doen?
Wat voor moeilijkheden zie je hierbij optreden?
Nou ja, als elke plugin een eigen thread heeft om in te werken, dan maakt het ook niet echt uit dat DownloadURL blocking is, andere plugins kunnen dan gewoon doorwerken. Dat is toch het hele probleem, of ligt het probleem ergens anders?
Maar voor zover ik weet haalt dat niets uit, daar de DownloadURL functie in het hoofdprogramma zit... Dus in de mainthread... Dan draaien de plugins misschien wel in threads, maar ze vragen allemaal aan de mainthread dezelfde functie op? Of zit ik verkeerd te denken?
Een functie zit niet in een bepaalde thread, een functie draait gewoon in de thread waarvandaan hij aangeroepen wordt.

Maar kun je eens een soort van sequence diagrammetje geven hoe de functies in de plugins nu worden aangeroepen, en wanneer? En ook eens van wat je nou eigenlijk wilt

Bijvoorbeeld:
- programma start op
- programma laadt plugin 1
- een functie in plugin 1 wordt aangeroepen
- plugin 1 roept DownloadURL aan om iets te downloaden
- ** app blocked tot download compleet is **
- programma laadt plugin 2
- enz.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
- programma start op
- programma laadt alle plugins
+ zoeken naar plugins
+ laadt plugin X
+ laadt functies van plugin X in een struct
- programma vraagt om iets te zoeken
+ programma vraagt aan plugin1 om iets te zoeken
+ **main programma blocked tot plugin1 gedaan heeft met zoeken**
+ programma vraagt aan pluginX om iets te zoeken
- programma toont resultaten.

Wat ik wil bereiken is:
- programma vraagt om iets te zoeken
+ programma vraagt aan alle plugins iet te zoeken
+ plugins returnen resultaten.
+ programma wacht tot het alle resultaten heeft
- programma toont resultaten.


Wat ik wil is dat ik tegelijk alles ga downloaden, en dan wacht tot ik alle resultaten heb. Op het moment download ik ze sequentieel...


Waar ik nu zit aan te denken is:
- programma vraagt iets te zoeken
* programma spawned threads met meegave van een threadID & de geexporteerde zoek-functie van de dll. [omdat je zegt dat een functie uitgevoerd wordt in de thread waaruit opgeroepen. Op deze manier roep ik in die thread de zoekfunctie aan in de dll, deze roept dan weer de Download-functie op in het hoofdprogramma. Dit gebeurd allemaal in een aparte thread, zodoende kan ik gewoon voort gaan met het versturen van 'aanvragen' in de andere threads. Op het einde van de zoekactie laat ik dan gewoon een event triggeren dat zegt "deze plugin heeft gedaan met downloaden"]
* programma gaat verder nadat tijd verstreken is/alle plugins gezocht hebben.

Klinkt dat als onzin of begin ik het een beetje te begrijpen?

[ Voor 6% gewijzigd door Verwijderd op 03-07-2004 07:54 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Wat je zou kunnen doen is een aparte download thread maken. Deze haalt zijn opdrachten uit de download queue, gevuld door de plugins. ( Geef de plugins een status code terug als ze dit doen eg DOWNLOAD_QUEUED oid )


Als de download thread klaar is met een download, vuurt deze een windows message af naar je main thread, die dan vervolgens je plugin een status doorgeeft DOWNLOAD_COMPLETE.

Je moet wat administratie bijhouden welke plugin welke download wilde, en welke url dat was, maar dat kan heel mooi met een std::vector/stl::multimap met daarin een leuke class..

Je plugins hoeven op die manier niet je main thread te blocken, en krijgen hun status events wel op dezelfde main thread.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 00:58
Je probleem is inderdaad dat je alle plugins sequentieel aanspreekt. .oisyn wees daar al op. Ik zou farlane's suggestie dus even links laten liggen.
Verwijderd schreef op 03 juli 2004 @ 07:52:
Waar ik nu zit aan te denken is:
- programma vraagt iets te zoeken
* programma spawned threads met meegave van een threadID & de geexporteerde zoek-functie van de dll. [omdat je zegt dat een functie uitgevoerd wordt in de thread waaruit opgeroepen. Op deze manier roep ik in die thread de zoekfunctie aan in de dll, deze roept dan weer de Download-functie op in het hoofdprogramma. Dit gebeurd allemaal in een aparte thread, zodoende kan ik gewoon voort gaan met het versturen van 'aanvragen' in de andere threads. Op het einde van de zoekactie laat ik dan gewoon een event triggeren dat zegt "deze plugin heeft gedaan met downloaden"]
* programma gaat verder nadat tijd verstreken is/alle plugins gezocht hebben.

Klinkt dat als onzin of begin ik het een beetje te begrijpen?
Dat klinkt alsof je het begint te begrijpen. :)

In je hoofdthread spawn je een aantal worker threads die elk een andere plug-in aanspreken. Als alle worker threads klaar zijn zijn de resultaten beschikbaar. Ondertussen kan je main thread gewoon messages afhandelen en blijf de GUI dus responsief.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Verwijderd schreef op 03 juli 2004 @ 07:52:
Waar ik nu zit aan te denken is:
... Op deze manier roep ik in die thread de zoekfunctie aan in de dll, deze roept dan weer de Download-functie op in het hoofdprogramma. Dit gebeurd allemaal in een aparte thread, zodoende kan ik gewoon voort gaan met het versturen van 'aanvragen' in de andere threads. Op het einde van de zoekactie laat ik dan gewoon een event triggeren dat zegt "deze plugin heeft gedaan met downloaden"]
Je moet wel erg goed oppassen hier met race conditites ed. Als ik het goed begrijp gaan al je threads dezelfde functie aanroepen. Zorg er dan voor dat die hele functie (dus ook alle andere functies die gebruikt worden) threadsafe is, dat je daar dus nooit globale en/of statische variabelen gebruikt. En mocht het noodzakelijk zijn, gebruik dan wel een locking mechanisme. Verder ook even linken met de threadsafe versie van libc.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Ik denk dat je met het 'thread per plugin' idee een heleboel problemen op de hals haalt ivm locking e.d.

Je kunt in een thread heel goed meerdere downloadstreams behandelen, en de tijd dat een plugin je main thread locked als hij een nieuwe download url wil aanbieden is minimaal.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 00:58
Je moet threads ook gebruiken voor taken die parallel uitgevoerd moeten/kunnen worden. Wat is de meerwaarde van het asynchroon downloaden van een bestand als de plug-in het resultaat daarvan nodig heeft voordat verder gegaan kan worden? Volgens mij is dat nihil. De downloadfunctie asynchroon maken heeft naar mijn idee dan ook weinig nut (eventueel zijn er nog andere situaties waarin dat anders ligt, maar dat kan ik uit de informatie van de TS niet opmaken).

Verwijderd

Als je er niet vies van bent om zo'n 35.000 regels aan source door te bladeren, kijk dan eens naar het JDAWN project: http://sourceforge.net/projects/jdawn of http://www.liacs.nl/~jdawn .

Hier is al precies gedaan wat jij nu lijkt te willen, thread pools, thread manager, plug-ins, en toevallig zelfs een loadUrl plug-in. Het is nog erg alfa allemaal, en er wordt de laatste tijd niet zoveel meer aan gedaan (lees bijna nix), maar mischien kun je er wat inspiratie uit opdoen.

Verwijderd

Topicstarter
De download functie asynchroon maken heeft inderdaad niet veel nut. Omdat ik de gedownloadde pagina nodig heb voor in te zoeken...
Maar als ik de volledige zoekopdracht asynchroon laat verlopen, heeft dit enorm veel nut natuurlijk. Want dan kan ik 10 zoekopdrachten tegelijk laten starten. Allemaal parallel.

Daarom ga ik niet met 1 thread werken, maar met 1 thread/plugin. Ik ben op het moment de op te roepen functies aan het thread-safe maken, zodat ik niet voor onaangename verrassingen kom te staan.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Verwijderd schreef op 04 juli 2004 @ 05:45:
De download functie asynchroon maken heeft inderdaad niet veel nut. Omdat ik de gedownloadde pagina nodig heb voor in te zoeken...
Bij je ts gaf je aan dat juist het downloaden je main thread locked, en nu zeg je dat het downloaden asynchroon maken niet veel nut heeft. Ikke niet begrijp.

Waaruit bestaat een 'zoekopdracht' nog meer, naast het downloaden ?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 00:58
farlane: wat ik er van begrijp is dat de TS een aantal plug-ins heeft. Bij een opdracht van de gebruiker moet voor elk van de plug-ins een commando worden uitgevoerd; elke plug-in gaat dan voor zichzelf een bestand downloaden en het resultaat parsen en met die gegevens iets doen.

In die situatie ligt het voor de hand om na het ontvangen van het commando een aparte thread te spawnen voor elke plug-in, zodat elke plug-in onafhankelijk zijn werk kan doen. De downloadprocedures binnen elke thread vinden dan gewoon synchroon plaats. De main thread is ondertussen vrij om window messages af te handelen en zo. Uiteindelijk rapporteren de threads hun resultaten via de message queue of op een andere manier.

disclaimer:
Dit is dus mijn interpretatie van het probleem. Als KaReL het nog even kan toelichten dan weten we zeker hoe het zit. :)

[ Voor 10% gewijzigd door Soultaker op 09-07-2004 11:48 ]

Pagina: 1