Toon posts:

[Kylix] Data uit worker thread naar main thread sturen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb de volgende situatie:

-Main thread die bestaat uit een aantal formulieren
-idTCPServer component (Indy 9) wat een aparte thread is (is standaard zo)


Die idTCPServer staat dus continu te luisteren of er wat binnenkomt en zodra er wat beschikbaar is voert die de OnExecute event uit.

In deze event bekijk ik wat precies de informatie is. Afhankelijk van deze informatie moet deze data doorgestuurd worden naar een bepaald formulier in de main thread.

Echter je kan niet zomaar vanuit die OnExecute event direct dat formulier aanroepen om zo de gegevens van de idTCPServer door te geven aan de procedure in dat formulier.

Dus in het formulier in de main thread heb ik een public procedure:

procedure HandleData(Data: String);

die verder de ontvangen data afhandelt in de main thread.

Normaal gesproken moet je dit oplossen met Synchronize. Alleen je kan dan geen parameters meegegeven. Dus hoe kan ik dan ooit die gegevens daar brengen?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

In je thread een method aanmaken die die handledata aanroept met de correcte params,. en dan een synchronize(dodata).

code:
1
2
3
4
Tthread.dodata;
begin
  form.handledata('woei');
end;

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op 08 April 2003 @ 16:51:
In je thread een method aanmaken die die handledata aanroept met de correcte params,. en dan een synchronize(dodata).
Ik maak dynamisch een TidTCPServer component aan. Dit creeert automatisch die aparte worker thread (listener thread). Vervolgens als er wat binnenkomt op die thread, start het een nieuwe thread (wat dan via de OnExecute aangegeven wordt). Dat is tenminste wat ervan begrepen heb hoe die Indy server werkt.

Maar ik moet dus die DoData in die thread klasse maken die gebruikt wordt in die OnExecute event? Maar ik zou niet weten hoe dat dan kan :?

Het is toch niet goed om een nieuwe klasse te maken die gebaseerd is op TidTCPServer en daar dan die DoData in te stoppen?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 08 April 2003 @ 18:47:
[...]
Ik maak dynamisch een TidTCPServer component aan. Dit creeert automatisch die aparte worker thread (listener thread). Vervolgens als er wat binnenkomt op die thread, start het een nieuwe thread (wat dan via de OnExecute aangegeven wordt). Dat is tenminste wat ervan begrepen heb hoe die Indy server werkt.

Maar ik moet dus die DoData in die thread klasse maken die gebruikt wordt in die OnExecute event? Maar ik zou niet weten hoe dat dan kan :?

Het is toch niet goed om een nieuwe klasse te maken die gebaseerd is op TidTCPServer en daar dan die DoData in te stoppen?
Het lijkt me dat het niet nodig is om de tIdTCPServer aan te passen om te bereiken wat je wilt. Weet je zeker dat die OnExecute in de context van een ANDERE thread word uitgevoerd, en niet stiekum met een synchronize al door de mainthread word uitgevoerd?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op 09 April 2003 @ 08:40:Weet je zeker dat die OnExecute in de context van een ANDERE thread word uitgevoerd, en niet stiekum met een synchronize al door de mainthread word uitgevoerd?
Net ff gekeken en als ik iets stuur naar programma B, dan wordt er een aparte thread gestart.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

Dat er een (extra) thread word gestart wil niet zeggen dat de onexecute ook in de context van de nieuwe thread draait ;)
Bij de onexecute krijg je als parameter een thread mee welke het event heeft gegenereerd. Dus nogmaals: weet je 100% zeker dat de onexecute NIET in de context van de mainthread runt?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op 09 april 2003 @ 09:37:
Dat er een (extra) thread word gestart wil niet zeggen dat de onexecute ook in de context van de nieuwe thread draait ;)
Bij de onexecute krijg je als parameter een thread mee welke het event heeft gegenereerd. Dus nogmaals: weet je 100% zeker dat de onexecute NIET in de context van de mainthread runt?
Nee dat weet ik niet 100% zeker. Maar hoe kan ik daar acher komen :) ?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

* Creepy stelt voor om gewoon direct het form te benaderen vanuit je onexecute. ;)

Als je een tidTCPServer op een form sleept, en dubbelklikt op de onExecute method dan komt die method erbij als method van je form (!!). Dus dan roept de tidTCPServer een method aan van je form. Conclusie: de onexecute method word in de context van de mainthread uitgevoerd. :)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op 09 April 2003 @ 10:20:Als je een tidTCPServer op een form sleept, en dubbelklikt op de onExecute method dan komt die method erbij als method van je form (!!). Dus dan roept de tidTCPServer een method aan van je form. Conclusie: de onexecute method word in de context van de mainthread uitgevoerd. :)
Dat zou dus betekenen dat je nooit meerdere dingen tegelijk kan uitvoeren als de idTCPServer verschillende berichten ontvangt?

Maar ik heb nog eens zitten testen. Als ik in de OnExecute van de idTCPServer die DoData rechtstreeks aanroep, loopt het programma nog wel eens vast. Doe ik het met synchronize loopt die niet vast.

Dat duidt er toch op dat het wel in verschillende threads uitgevoerd wordt?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 09 april 2003 @ 11:14:
[...]
Dat zou dus betekenen dat je nooit meerdere dingen tegelijk kan uitvoeren als de idTCPServer verschillende berichten ontvangt?
Ach... het moet toch allemaal runnen op 1 processor die ook enige moeite heeft met 2 of meer dingen tegelijk doen ;)
Maar ik heb nog eens zitten testen. Als ik in de OnExecute van de idTCPServer die DoData rechtstreeks aanroep, loopt het programma nog wel eens vast. Doe ik het met synchronize loopt die niet vast.

Dat duidt er toch op dat het wel in verschillende threads uitgevoerd wordt?
En die dodata is een method van je form toch? Hmm.. vreemd. Je weet zeker dat het aan het feit ligt dat er van meerdere threads wordt gebruikt? Dan zit er toch echt maar 1 ding op en dat is een subklasse maken van TidTCPserver en in de thread dan die extra method aanmaken.
Tja.. het blijft gokken, aangezien de source van die dingen niet bij Delphi zit ;(

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Indy events worden altijd op een andere thread dan de main thread ge-fired. Als je in zo'n event iets wil doen met VCL forms zal je moeten synchronizeren op de main thread. Wat ik zelf vaak gebruik in een routine om zeker te weten dat deze niet op een andere thread dan de main thread wordt aangeroepen is:

code:
1
Assert( GetCurrentThreadId = MainThreadID );


Dit geeft gelijk een duidelijke waarschuwing als je per ongeluk toch deze routine aan roept op een andere thread zoals bijv een indy event handler. Het is ook gelijk duidelijk voor een ander die je code bekijkt

PS Indy source zit wel bij Delphi

[ Voor 4% gewijzigd door martijn_brinkers op 09-04-2003 11:44 ]


Verwijderd

Topicstarter
Iedere OnExecute event wordt uitgevoerd in een nieuw gecreeerde thread. Dat weet ik nu zeker.

Alleen ik weet nog niet precies waar ik nu die DoData procedure moet plaatsen. Ik heb hem nu in de TXMLServer klasse staan:

Delphi:
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
52
  TXMLServer = class
  private
    idTCPServer: TIdTCPServer;
    IdThreadMgrPool: TIdThreadMgrPool;
    Input: String;
    procedure IdTCPServerExecute(AThread: TIdPeerThread);
    procedure ShowInput;
    procedure DoData;
  protected
  public
    constructor Create(Port: Integer);
    destructor Destroy; override;

    procedure SetServer(Enabled: Boolean);
    function GetServer: Boolean;
  end;



procedure TXMLServer.IdTCPServerExecute(AThread: TIdPeerThread);
var XMLDocument: TXMLDocument;
begin
  try
    Input := AThread.Connection.ReadLn;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;

  // Stuur een antwoord terug naar de client
  try
    AThread.Connection.WriteLn('ACK');
  except
    on E: Exception do
    begin
      ShowMessage('Error send ACK: ' + E.Message);
    end;
  end;

  AThread.Synchronize(DoData);

  AThread.Terminate;
end;


procedure TXMLServer.DoData;
begin
  // Hier wordt een procedure uit een bepaald form uitgevoerd met als 
  // parameter: Input
end;


In de OnExecute roep ik dan die DoData aan via Synchronize.

Kan dit dan geen problemen veroorzaken? Want het kan toch zo zijn dat die OnExecute meerdere malen uitgevoerd wordt dat ze allemaal dus input wijzigen en vervolgens DoData aanroepen.

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
zoals ik al in je andere draad had aangegeven mag je ShowMessage niet in een andere thread gebruiken dan de main thread. Dus je code is nog niet goed.

Verwijderd

Topicstarter
TijnFLiP schreef op 09 april 2003 @ 13:41:
zoals ik al in je andere draad had aangegeven mag je ShowMessage niet in een andere thread gebruiken dan de main thread. Dus je code is nog niet goed.
Oh ja ik ben vergeten om in de exception het ook via Synchronize aan te roepen. Dom |:(

Maar voor de rest is het wel goed zo met het wijzigen van de input variabele via de OnExecute event en dan vervolgens de DoData aanroepen via Synchronize?

Wat ik denk dat er fout kan gaan is dat als 2 aparte threads (gestart via de OnExecute) allebei de input variabele willen veranderen dat het dan fout gaat?? De laatste overschrijft dan de waarde, zodat ze allebei dezelfde data (=waarde van input variabele) hebben??

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

Het beste zou denk ik zijn om de input aan de thread te koppelen, en dan de OnExecute a.d.v. de thread param de input te laten lezen.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op 09 April 2003 @ 13:54:
Het beste zou denk ik zijn om de input aan de thread te koppelen, en dan de OnExecute a.d.v. de thread param de input te laten lezen.
Klopt, alleen het probleem is dat die thread niet door mij gecreeerd wordt, maar dat indy die zelf aanmaakt. Dus ik heb niet een eigen thread klasse met die variabele en procedure.


Edit:

Ik denk dat ik een goede oplossing heb:

In de OnExecute van de TidTCPServer maak ik een instantie aan van TXMLHandling. (klasse gebaseerd gewoon op TObject).
Vervolgens geef ik de input dat ik ontvangen heb van de idTCPServer door aan deze XMLHandling instantie.

Daar wordt dan via de Synchronize de procedure aangeroepen DoData (die dus dan in de klasse TXMLHandling aanwezig is). DoData roept dan een bepaald formulier aan in de main thread.

Ik denk dat ik dan geen problemen krijg.

[ Voor 39% gewijzigd door Verwijderd op 09-04-2003 14:29 ]


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
je kan TIdPeerThread.Data voor dat soort dingen gebruiken. Je kan een instantie van een eigen class maken waarin je gegevens stopt behorende bij de thread en een referentie naar die classe in Data stoppen (voor dit soort dingen is Data ook erin gestopt). Je kan denk ik ook de thread local storage (tls) gebruiken door een global var als ThreadVar te declareren (is niet zo mooi als de andere oplossing maar wel makkelijk :).
Pagina: 1