Announcement

Collapse
No announcement yet.

Synchronize o. Cirticalsection

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Synchronize o. Cirticalsection

    <font size="2" face="Verdana">Hallo<br>
    ich möchte mir eine Komponete (TGraphicControl) schreiben,<br>
    die während einer längeren Datenbankabfrage anzeigt, dass etwas<br>
    passiert. Es läuft z.B. ein kleines Rechteck von links nach
    rechts<br>
    und wieder zurück. Damit sich die Komponente auch zeichnet
    erzeugt<br>
    Sie einen Thread. Innerhalb der Execute Methode (siehe Code) rufe
    ich dann<br>
    Zeichenmethode der Komponente auf. Wenn ich dafür Synchronize
    verwende<br>
    passiert gar nichts. Benutze ich hingegen eine CriticalSection
    zeichnet<br>
    sich die Komponente während der Datenbankabfrage. Ist der
    Zugriff auf die VCL<br>
    innerhalb einer CriticalSection genau so sicher wie mit<br>
    Synchronize? Außerdem gibt es ein Problem, wenn die Komponente<br>
    auf einem anderen Formular sitzt. D.h. wenn ich eine zweite Form<br>
    anzeige und dort die Datenbankabfrage starte, zeichnet sich die<br>
    Komponate nicht neu ?!? TAnimate kann das. </font></p>
    <br>
    <pre>
    </code><font color="#800000" size="2" face="Verdana"><code><b>procedure</b></code></font><font
    size="2" face="Verdana"><code> TGaugeThread.Execute;
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>begin</b></code></font><font
    size="2" face="Verdana"><code>
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>While</b></code></font><font
    size="2" face="Verdana"><code> </code></font><font
    color="#800000" size="2" face="Verdana"><code><b>Not</b></code></font><font
    size="2" face="Verdana"><code> Terminated </code></font><font
    color="#800000" size="2" face="Verdana"><code><b>do</b></code></font><font
    size="2" face="Verdana"><code>
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>begin</b></code></font><font
    size="2" face="Verdana"><code>
    CS.Enter;
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>Try</b></code></font><font
    size="2" face="Verdana"><code>
    GetInterval;
    FGauge.PaintGauge;
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>Finally</b></code></font><font
    size="2" face="Verdana"><code>
    CS.Leave;
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>end</b></code></font><font
    size="2" face="Verdana"><code>;
    Sleep(FInterval);
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>end</b></code></font><font
    size="2" face="Verdana"><code>;
    </code></font><font color="#800000" size="2" face="Verdana"><code><b>end</b></code></font><font
    size="2" face="Verdana"><code>;</code></font><code>
    </pre>

    <p><br>
    <font size="2" face="Verdana">:-) Jens Schumann </font></p>

  • #2
    Hallo,

    nicht ohne Grund wird eine neue TThread-Unit mit einem langen Kommentarblock generiert, der mit dem Satz "<i>Wichtig: Methoden und Eigenschaften von Objekten in der VCL können nur in einer Methode namens Synchronize verwendet werden</i>" beginnt.

    Die Methode <b>Synchronize</b> sorgt dafür, dass der Programmcode im Kontext des primären Threads der VCL ausgeführt wird. Ist dieser primäre Thread ausgelastet (d.h. er fragt nicht die Botschaftswarteschlange ab), wird die über Synchronize übergebene Aufgabe nicht abgearbeitet. Dies ist die Erklärung dafür, dass sich die Komponente über diesen Weg nicht neu zeichnen kann (Synchronize = nur ein Thread darf gleichzeitig laufen).

    Der alternativ eingeschlagene Weg über eine <b>Critical Section</b> ist in dem o.g. Beispiel völlig wirkungslos. Eine Critical Section verhindert nur, dass mehrere Threads gleichzeitig den geschützten Code-Bereich durchlaufen. Da die VCL (primärer Thread der Anwendung) jedoch <b>niemals</b> diesen Bereich aufruft, und auch kein eigener zweiter Thread dies macht, ist das Einklammern in eine Critical Section überflüssig. Diese Implementierung ist russisches Roulette, es ist nur eine Frage der Zeit, bis es knallt :-)

    Die <b>TAnimate</b>-Komponente ist nur ein VCL-Wrapper auf das Win32-Control ANIMATE. Und dieses Control ist ein eigenständiges Fenster, dass von Microsoft mit Visual C++ geschrieben wurde. Daher wird hier Synchronize nicht benötigt.

    Wenn man mit Delphi so etwas nachbauen will, muss man das einbettende Formular für den Darstellungsbereich der Animation in eine DLL auslagern. Dort wird eine Formularinstanz erzeugt, die sich als Childfenster (BorderStyle = bsNone) in das Formular der Anwendung einbettet:
    <pre>
    procedure TForm_ZB.CreateParams(var Params: TCreateParams);
    begin
    inherited CreateParams(Params);
    with Params do
    begin
    Style := WS_CHILD or WS_VISIBLE;
    WndParent := hParent;
    end;
    end;
    </pre>
    Die DLL exportiert eine Schnittstellenprozedur, bei der das Fensterhandle des "Zielbereichs" als Parameter übergeben wird:
    <pre>
    procedure E_CreateTV_ZB(aParent: Integer); stdcall;
    </pre>
    In dieser Schnittstellenprozedur ermittelt das DLL-Formular, wie gross es sich darstellen muss:
    <pre>
    procedure E_CreateTV_ZB(aParent: Integer); stdcall;
    var
    aRect : TRect;
    begin
    try
    hParent := aParent;
    GetWindowRect(aParent, aRect);
    // Formular als Childfenster erzeugen + Größe anpassen
    Form_ZB := TForm_ZB.Create(Application);
    Form_ZB.Width := aRect.Right - aRect.Left - 5;
    Form_ZB.Height := aRect.Bottom - aRect.Top - 5;
    Form_ZB.Visible := True;
    except
    // Exceptions unbedingt abfangen
    MessageBeep(0);
    end;
    end
    </pre>
    Solange weder die Anwendung noch die DLL Runtime-Packages verwenden, sollte dieser Weg machbar sein. Ich habe das jedoch noch niemals mit einem externen Thread ausprobiert

    Comment

    Working...
    X