[Delphi] AVI afspelen tijdens openen TCustomConnection

Pagina: 1
Acties:

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23-08 22:26

Tomatoman

Fulltime prutser

Topicstarter
Het openen van een TCustomConnection (TDCOMConnection, TWebConnection, TSocketConnection) kan een tijdje duren. Tijdens het openen wil ik een AVI afspelen in een TAnimate component. Probleem: De AVI bevriest onmiddellijk zodra ik de connectie open met Connect := True en loopt weer verder zodra de connectie een paar seconden later daadwerkelijk is geopend :(.

Ik wil door middel van die AVI juist laten zien dat er nog sjoege in mijn app zit en dat hij niet hangt. Dat kan ik zo wel schudden natuurlijk. Suggesties?

Achtergrondinfo: de connectie wordt alleen gemaakt om te testen of hij goed functioneert. Er hangen geen andere componenten aan de connectie.

Een goede grap mag vrienden kosten.


  • Wortelpudding
  • Registratie: Februari 2002
  • Niet online
Je kunt Indy downloaden. Dit is op zich een suite met allemaal componenten voor netwerkprocollen, maar hij heeft ook een TAntiFreeze component.
Je probleem is namelijk dat tijdens het openen van die connectie er helemaal geen messages meer worden afgehandeld door je applicatie. Met die TAntiFreeze component wordt dit gedetecteert en worden je messages automatisch wel afgehandeld.

Je kunt natuurlijk ook het openen van zo'n connectie asynchroon doen in een aparte thread, maar ik heb zo'n vaag vermoeden dat dat toch iets meer tijd gaat kosten :P.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Waarschijnlijk wordt er tijdens de Connect := True zoveel processortijd gevraagt dat er geen paint messages worden afgehandeld voor je AVI. Een simpele oplossing zou een TTimer kunnen zijn op je AVI form die om de zoveel seconden een Application.ProcessMessages; doet.

/edit
De TAntiFreeze die MrHuge voorsteld doet hetzelfde als wat ik net voorstelde

[ Voor 14% gewijzigd door LordLarry op 17-03-2003 09:36 ]

We adore chaos because we like to restore order - M.C. Escher


  • Wortelpudding
  • Registratie: Februari 2002
  • Niet online
LordLarry schreef op 17 March 2003 @ 09:34:
Waarschijnlijk wordt er tijdens de Connect := True zoveel processortijd gevraagt dat er geen paint messages worden afgehandeld voor je AVI. Een simpele oplossing zou een TTimer kunnen zijn op je AVI form die om de zoveel seconden een Application.ProcessMessages; doet.
TTimer is geen oplossing... Die stuurt namelijk ook messages (WM_TIMER) en het probleem is nou juist dat die messages op dat moment niet afgehandeld worden omdat de message-loop geblocked wordt. De oorzaak hiervan is dat het openen van zo'n connectie waarschijnlijk in een event-handler gebeurt.

  • killermar
  • Registratie: Augustus 2002
  • Laatst online: 12-07 08:05
Ik zou het het communiceren met de server (dus ook het verbinden) in een aparte thread uitvoeren.

  • Wortelpudding
  • Registratie: Februari 2002
  • Niet online
killermar schreef op 17 March 2003 @ 10:01:
Ik zou het het communiceren met de server (dus ook het verbinden) in een aparte thread uitvoeren.
Is idd wel de mooiste oplossing. Een event-handler zou eigenlijk nooit al teveel tijd in beslag mogen nemen omdat een event handler niet bedoeld is om veel tijd in beslag te nemen. Je zou je applicatie dus zo moeten ontwerpen dat event-handlers nooit blocking calls (zoals connectie maken, WaitForSingleObject, etc...) gebruiken, want hiermee blokkeer je dus gelijk de hele message-loop van je window en in het ergste geval van je hele applicatie. Als dit wel zo is, dan moet je er sterk over nadenken om een aparte thread te gebruiken om dit soort problemen te voorkomen.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Wortelpudding schreef op 17 maart 2003 @ 09:37:
[...]
TTimer is geen oplossing... Die stuurt namelijk ook messages (WM_TIMER) en het probleem is nou juist dat die messages op dat moment niet afgehandeld worden omdat de message-loop geblocked wordt. De oorzaak hiervan is dat het openen van zo'n connectie waarschijnlijk in een event-handler gebeurt.
Dat wist ik inderdaad, maar ik had gedacht dat WM_TIMER messages voorrang kregen boven de andere. Dit blijkt niet het geval en dus zal mij oplossing niet echt werken. Je hebt gelijk.

Ook heb ik de TAntiFreeze bekeken van Indy, maar ook deze zal je niet helpen. Het wordt namelijk als vervanger van Application.Processages gebruikt. Door de hele code van Indy heen wordt de GAntiFreeze.DoProcess aangeroepen.

Het gebruik van een andere thread wordt wel erg lastig hier, omdat het een component is die in verbinding staat met andere componenten. Er is geen scheiding in aan te brengen en bovendien zal je veel synchronizatie moeten toepassen. Als die synchronizatie maakt je applicatie weer veel langzamer.

We adore chaos because we like to restore order - M.C. Escher


  • killermar
  • Registratie: Augustus 2002
  • Laatst online: 12-07 08:05
LordLarry schreef op 17 maart 2003 @ 11:39:
[...]

Het gebruik van een andere thread wordt wel erg lastig hier, omdat het een component is die in verbinding staat met andere componenten. Er is geen scheiding in aan te brengen en bovendien zal je veel synchronizatie moeten toepassen. Als die synchronizatie maakt je applicatie weer veel langzamer.
Multithreading (met bijbehorende synchronisatie) is iets waar je niet bang voor moet zijn als je met communicatie bezig bent.
Waarom het koppelen van componenten een probleem zou zijn in een multithreaded app begrijp ik niet. (die koppelingen zijn er volgens tomatoman trouwens niet) Als er componenten blocken tijden de communicatie zijn ze (meestal) thread safe.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

De VCL is niet thread-safe en dus zou je geen variablen (componenten) van andere threads aan moeten kunnen roepen, behalve als je zelf voor de synchronizatie zorgt. Je zou in de VCL source die routines kunnen toevoegen, maar dat lijkt mij niet erg netjes. Als je dat niet doet heb je niet de volledige controle over het component en de acties die het uitvoerd en je kan daarmee het thread-sage zijn niet garanderen. Als de TS het component dynamisch in die nieuwe thread creeert en daar geen andere variablen/functies van andere threads aan koppelt heb je misschien een kans, maar ik weet niet of er ergens in de source van dat component een globable variable staat...

Kortom: Bang moet je er niet voor zijn, wel erg voorzichtig.

We adore chaos because we like to restore order - M.C. Escher


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23-08 22:26

Tomatoman

Fulltime prutser

Topicstarter
Op aanraden van de Tweakers-gemeenschap heb ik de Open() actie in een aparte thread gegooid en dat werkt prima. De connection wordt gecreëerd in de context van de main thread en wordt vervolgens geopend in de context van de aparte thread, zodat de AVI vrolijk blijft doorlopen.

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
53
54
55
56
57
58
59
60
61
62
63
64
unit ConnectThread;

interface

uses
  Classes, SysUtils, Forms, DB, ComObj, ActiveX;

type
  { TConnectThread is used to open a TCustomConnection descendant
    (TDCOMConnection, TSocketConnection, TWebConnection) asynchronously.

    TDCOMConnection can be opened asynchronously more than once without
    problems, but TSocketConnection and TWebConnection will produce an
    exception when opened a second time. }

  TConnectThread = class(TThread)
  private
    FConnection: TCustomConnection;
    FDone: Boolean;
    FException: Exception;
    FOnException: TExceptionEvent;
    procedure DoException;
  protected
    procedure Execute; override;
  public
    constructor Create(Connection: TCustomConnection;
      CreateSuspended: Boolean);
    property Done: Boolean read FDone;
    property OnException: TExceptionEvent read FOnException
      write FOnException;
  end;

implementation

procedure TConnectThread.DoException;
begin
  FOnException(Self, FException);
end;

procedure TConnectThread.Execute;
begin
  try
    FConnection.Open;
  except
    on E: Exception do
      if Assigned(FOnException) then
      begin
        FException := E;
        Synchronize(DoException);
      end;
  end;
  FDone := True;
end;

constructor TConnectThread.Create(Connection: TCustomConnection;
  CreateSuspended: Boolean);
begin
  FConnection := Connection;
  inherited Create(CreateSuspended);
end;

initialization
  CoInitFlags := COINIT_MULTITHREADED;
end.

Nu de verbinding TestConnection openen:
Delphi:
1
2
3
4
5
6
7
8
9
  ConnectThread := TConnectThread.Create(TestConnection, True);
  try
    ConnectThread.OnException := ConnectThreadException;
    ConnectThread.Resume;
    while not ConnectThread.Done do
      Application.ProcessMessages;
  finally
    ConnectThread.Free;
  end;

[ Voor 15% gewijzigd door Tomatoman op 17-03-2003 22:34 ]

Een goede grap mag vrienden kosten.


  • Wortelpudding
  • Registratie: Februari 2002
  • Niet online
tomatoman schreef op 17 March 2003 @ 22:23:
Op aanraden van de Tweakers-gemeenschap heb ik de Open() actie in een aparte thread gegooid en dat werkt prima.
Hij's braaf ;) :+
Pagina: 1