AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Synchronize und die Messagequeue

Ein Thema von igel457 · begonnen am 2. Jan 2010 · letzter Beitrag vom 3. Jan 2010
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#1

Synchronize und die Messagequeue

  Alt 2. Jan 2010, 18:41
Hallo,

ich habe ein kleines Problem mit den Methoden "TThread.Synchronize" bzw. "TThread.Queue". Ich verwende diese Methoden um Events aus meinem Audiosystem mit dem Hauptthread der VCL zu synchronisieren. Intern fügt "Synchronize" einen Record mit den Informationen über die übergebene Funktion zu einer Liste hinzu und sendet dann via "PostMessage" die Message WM_NULL an den Hauptthread. Wird dort WM_NULL empfangen so wird die Liste der zu synchronisierenden Methoden abgearbeitet. Soweit die Theorie.

Nun ergibt sich aber folgendes Problem: Scheinbar arbeitet meine Anwendung nur dann WM_NULL ab, wenn eine andere Message eintrifft - zum Beispiel wenn die Maus bewegt wird oder ein Timer-Event ausgelöst wird. Hierdurch stauen sich in meinem eigenen Synchronisierungsthread die "Anträge". Erst wenn man die Maus eine Weile über einem Fenster der Anwendung bewegt, werden die Events nach und nach abgearbeitet.

Hier ein kurzer Codeauszug:
Delphi-Quellcode:
procedure TAuSyncMgr.Execute;
begin
  try
    while not Terminated do
    begin
      while true do
      begin
        FCurMem := nil;
        FDeletedCurMem := false;

        FCritSect.Enter;
        try
          if FCallList.Count > 0 then
            FCurMem := PThreadMethod(FCallList[0]);
        finally
          FCritSect.Leave;
        end;

        if FCurMem = nil then
          break;

        try
          try
            {$IFNDEF DO_NOT_USE_VCL}
            //Erst nach dem Abarbeiten von "FCurMem^" durch Synchronize kehrt die Funktion zurück.
            //Das ist auch gut so. Jedoch wird FCurMem^ erst nach dem Eintreffen einer Windowmessage
            //wie "WM_MOUSEMOVE" abgearbeitet. Das ist nicht so schön.
            Synchronize(FCurMem^);
            {$ELSE}
            FCurMem^;
            {$ENDIF}
          finally
            if not FDeletedCurMem then
            begin
              //Remove the element from the list
              FCritSect.Enter;
              try
                FCallList.Delete(0);

                //Free the memory reserved for the method pointer
                FreeMem(FCurMem, SizeOf(TThreadMethod));
              finally
                FCritSect.Leave;
              end;
            end;
          end;
        except
          //
        end;
      end;
      Sleep(1);
    end;
  except
    //
  end;
end;
Den ganzen Code gibt es hier: http://audorra.svn.sourceforge.net/v...21&view=markup

Hat jemand eine mögliche Lösung für das Problem? Das Ganze sollte keine Änderung am Code des Endanwenders (sprich Formulare etc.) benötigen, sondern sich auf meinen Bibliothekscode beschränken. Einen Timer zu Formular hinzuzufügen (was übrigens zu langsam ist, da ich ca. 50-100 Events pro Sekunde auf diese Weise synchronisiere), ist also keine Lösung.

Ich hoffe mir kann hier jemand helfen.

Schon einmal Danke,
Andreas
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#2

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 18:53
Eventuell wird WM_NULL (ob von der VCL oder Windows oder vom Weihnachstmann) etwas anders behandelt. Als aller ersten Versuch würde ich eine eigene WM_USER + X Message mal ausprobieren statt WM_NULL. Das wäre ohnehin sauberer, da WM_NULL durchaus einen Sinn hat: Nämlich den, dass man davon ausgehen können soll, dass eine Anwendung ausser der Abarbeitung der Message keine anderen Operationen als Reaktion auf die Message ausführt. Ein Scheduler könnte damit also z.B. prüfen ob ein Programm nicht abgestürzt ist indem es in Pulsen WM_NULL broadcastet, was bei dir dann auf einmal echte Programmlogik nach sich zöge. (Ich weiss nicht ob Windows das nicht auch in echt so macht, aber es wäre eine gute Möglichkeit.)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#3

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 19:33
Hallo,

erstmal Danke für die Antwort.

In der Tat erreicht die Message "WM_NULL" niemals die Messagequeue des TApplication-Objekts. Dort steht:

Delphi-Quellcode:
WM_NULL:
  CheckSynchronize;
Diese Zeile wird nie Aufgerufen!

Zusätzlich wird "CheckSynchronize" nach jeder verarbeiteten Message (Also in Application.Idle) aufgerufen - das ist das, was ich durch bewegen der Maus auslöse.

Ersetzen der Zeile
Delphi-Quellcode:
procedure TApplication.WakeMainThread(Sender: TObject);
begin
  PostMessage(Handle, WM_NULL, 0, 0);
end;
Durch
Delphi-Quellcode:
const
  WM_SYNCHRONIZE_THREADS = WM_USER + 1187;

PostMessage(Handle, WM_SYNCHRONIZE_THREADS, 0, 0);
bringt leider keine Besserung. Die Message wird gar nicht empfangen. Sende ich die Message jedoch an Form1.Handle und nicht TApplication.Handle, so funktioniert das Ganze. Hat jemand eine Erklärung für dieses Verhalten?
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#4

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 21:46
Das könnte evtl. daran liegen, dass das Application-Formular nicht sichtbar ist. Ich kann es nicht mit Bestimmtheit sagen, aber ich kann mir vorstellen, dass dann entweder manche Messages garnicht verschickt, oder aber nicht verarbeitet werden - entweder auf Seiten des OS, oder der VCL. Ich hatte erst an die Unterscheidung von "WM_" Messages zu "CM_" Messages gedacht, aber es ist ja dann auch wieder WM_MOUSE_MOVE wenn ich nicht irre.
Wenn du den Source hast, wäre es vermutlich hilfreich mal in die Message-Loop von TApplication zu schauen. Vielleicht ist da ja schon was erkennbar, dass irgendwo unterschieden wird. Das ist jetzt aber auch nur ein Versuch einer Idee, ich hab hier leider kein Delphi zum genau nachschauen.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Astat

Registriert seit: 2. Dez 2009
Ort: München
320 Beiträge
 
Lazarus
 
#5

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 21:47
Zitat von igel457:
Hat jemand eine Erklärung für dieses Verhalten?
Hallo igel457, du verwendes das TApplication Handle, und nicht das Handle des Controls (TForm) in dem die zugehörige WndProc werkelt.

lg. Astat
Lanthan Astat
06810110811210410503210511511603209711003210010110 9032084097103
03211611111604403209711003210010110903210010510103 2108101116122
11610103209010110510810103206711110010103210511003 2068101108112
10410503210310111509910411410510109810111003211910 5114100046
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#6

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 21:57
Zitat von Medium:
Wenn du den Source hast, wäre es vermutlich hilfreich mal in die Message-Loop von TApplication zu schauen.
Um der Verwirrung vorzubeugen: Die Codeauszüge bezogen sich auf die Message-Loop von TApplication Dort wird WM_NULL abgefangen und "CheckSynchronize" aufgerufen. Dies wird jedoch nie ausgelöst, auch wenn ich WM_NULL (überall) durch irgendwas anderes ersetze.

Lasse ich die Message jedoch an mein Formular schicken und fange sie dort ab, dann geht es.

Das mit der Sichtbarkeit wäre eine Erklärung - die Frage ist dann jedoch, warum die Leute von (damals) Borland das so implementiert haben. Schließlich war TApplication auch schon bei Delphi 1 unsichtbar. Die Synchronisierung hat also noch nie richtig funktioniert.
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Astat

Registriert seit: 2. Dez 2009
Ort: München
320 Beiträge
 
Lazarus
 
#7

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 22:11
Zitat von igel457:
Lasse ich die Message jedoch an mein Formular schicken und fange sie dort ab, dann geht es.
funktioniert.
Ok, zeig doch mal deine Zuweisung der Synchronize methode, scheint ja so zu sein, als ob die

PThreadMethod(FCallList[0]); in der Luft hängt!?

Astat
Lanthan Astat
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#8

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 22:13
Delphi-Quellcode:
PostMessage(Application.Handle, WM_NULL, 0, 0);
und
SendMessage(Application.Handle, WM_NULL, 0, 0);
bei mir lösen beide Varianten
Delphi-Quellcode:
WM_NULL:
  CheckSynchronize;
aus

Application.Handle muß schon sein, denn immerhin steckt dieses in der WindowProc des Application-Fensters.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 22:16
Also die Sache über WM_Null funktioniert. Es wird zigfach eingesetzt, da es ja der Code von Delphi ist und den kaum einer ändern wird.
Das Synchronize Probleme macht und mit Bedacht eingesetzt werden muss ist klar:
  1. Man kann nur mit dem MAinThread synchronisieren
  2. Man kann synchronize nicht in einer DLL nutzen
  3. Der MainThread muss wartend sein (ist ja soweiso sinnvoll)
  4. ...
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#10

Re: Synchronize und die Messagequeue

  Alt 2. Jan 2010, 22:41
Der Fehler scheint irgendwie in meinem Projekt zu liegen.

Erstelle ich eine leere VCL-Formularanwendung und schreibe
PostMessage(Application.Handle, WM_NULL, 0, 0); in OnFormCreate, so wird WM_NULL ordnungsgemäß empfangen.

Füge ich denselben Code in die Betroffene Anwendung, an die selbe Stelle, so ist dies nicht der Fall. Ich muss da wohl mal ein wenig suchen...
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz