Autor |
Beitrag |
Elrond
      
Beiträge: 22
|
Verfasst: Do 16.10.08 01:04
Hallo allerseits,
ich brauche ein wenig Hilfe. Seit ein paar Wochen beschäftige ich mit mit Delphi 5. Bisher kam ich trotz Start bei Null recht gut klar, aber jetzt hänge ich fest.
Problem: Ich habe ein rechenintensives Programm geschrieben, welches ich bei Bedarf per Button abbrechen möchte, da unter gewissen Bedingungen minutenlang gerechnet und wie wild Informationen in ein StringGrid geschrieben werden.
Um auf Interrupts reagieren zu können, habe ich dafür gesorgt, dass öfters Application.ProcessMessages aufgerufen wird. Ein Abbruch-Button ist mit einer OnClick-Prozedur verbunden, aber bedauerlicherweise passiert gar nichts und ich muss das Programm dann per Task-Manager killen.
Für Ratschläge und Hilfe wäre ich außerordentlich dankbar.
Grüße
Elrond Moderiert von Narses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Do 16.10.2008 um 01:30
|
|
ub60
      
Beiträge: 764
Erhaltene Danke: 127
|
Verfasst: Do 16.10.08 01:21
Mit einem Abbruch-Button eine globale Variable setzen.
In der Rechenschleife die Variable abfragen und dann gegebenenfalls Schleife verlassen.
ub60
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 01:28
Alles schon probiert. Die OnClick-Prozedur macht genau das und funktioniert auch prima, solange mein Rechenmonster nicht läuft. Dann erhält die Prozedur trotz Application.ProcessMessages (wird laut Debugger regelmäßig ausgeführt) einfach nicht die Kontrolle und dann wird die globale Variable natürlich auch nicht gesetzt.
Elrond
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 16.10.08 01:31
Moin und  im Forum!
Elrond hat folgendes geschrieben : | Alles schon probiert. |
Dann wäre jetzt der Zeitpunkt für etwas Code, wie sollen wir sonst rausfinden, was da hakt?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Dunkel
      
Beiträge: 682
Mac OS X Snow Leopard
Xcode 3.1
|
Verfasst: Do 16.10.08 01:53
Hallo und willkommen im Forum!
Applicatin.ProcessMessages(); sollte nach Möglichkeit vermieden werden, das ist ungefähr genau so pöse wie goto und Konsorten.
Lager Deine lang andauernde Berechnung in eine Thread aus, diesen kannst Du, nach Bedarf, einfach absch(l)ießen; VCL-Zugriffe synchronisieren natürlich nicht vergessen.
_________________ Ich streite einsam mich mit dieser Oberflächenwelt
Gutes sei ein löblich Brot von dem ich zehre - bis zum Tod [Das Ich - Im Ich]
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 16.10.08 02:08
Moin!
Dunkel hat folgendes geschrieben : | Applicatin.ProcessMessages(); sollte nach Möglichkeit vermieden werden, das ist ungefähr genau so pöse wie goto und Konsorten. |
Na, wir wollen mal nicht übertreiben.  (und nicht in eine goto-Diskussion abgleiten!  )
In einer "vernünftig" konzipierten VCL-Anwendung ist das kein Problem (die Controls müssen halt passend zum aktuellen Programm-Zustand de-/aktiviert sein!).  Andersrum: wenn du mit APM Probleme bekommst, hast du einen fetten Bug in deinem Ereignisverarbeitungskonzept.
Dunkel hat folgendes geschrieben : | Lager Deine lang andauernde Berechnung in eine Thread aus, diesen kannst Du, nach Bedarf, einfach absch(l)ießen; VCL-Zugriffe synchronisieren natürlich nicht vergessen. |
Wenn er schon mit APM nicht klar kommt, dann wird das ja mit Threads sicher besser funktionieren...
@ Elrond: Zeig mal deinen Code, dann sehen wir weiter.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Dunkel
      
Beiträge: 682
Mac OS X Snow Leopard
Xcode 3.1
|
Verfasst: Do 16.10.08 02:23
_________________ Ich streite einsam mich mit dieser Oberflächenwelt
Gutes sei ein löblich Brot von dem ich zehre - bis zum Tod [Das Ich - Im Ich]
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 16.10.08 03:10
Moin!
Dunkel hat folgendes geschrieben : | VCL hin, VCL her, in einer "vernünftig" konzipierten Anwendung ist (ich habe ein wenig darüber nachgedacht, was das bedeutet) APM nicht von Nöten. |
Ich habe nicht bestritten, das APM (normalerweise) unnötig ist. vielleicht hast du also doch noch nicht lange genug drüber nachgedacht? *g*
Dunkel hat folgendes geschrieben : | Und pöse ist es trotzdem (mehrfach gefeuerte Ereignisse und Messages & Co., schwer zu debuggen ist es ebenfalls) |
Es ist weder "pöse", noch wird wird da was mehrfach gefeuert, wenn man eine VCL-konforme Anwendung hat.  Glaubst du nicht? Dann beweise das Gegenteil (Code!).  Ich wiederhole mich gerne, aber begrenzt: wenn du deine Anwendung/Controls z.B. über einen Zustand im Griff hast, dann spielt es keine Rolle, ob du APM aufrufst  es wird dann einfach keine Probleme geben, wenn man es trotzdem aufruft.
Dunkel hat folgendes geschrieben : | Narses hat folgendes geschrieben : | Wenn er schon mit APM nicht klar kommt, dann wird das ja mit Threads sicher besser funktionieren...  |
Das hoffe ich doch...  |
Das hoffe ich zwar auch  aber die Wahrscheinlichkeit ist gegen uns...
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 15:47
Hallo Leute,
erstmal herzlichen Dank für eure Kommentare. Bedenkt bitte, dass ich Delphi vor 3 Wochen zum ersten mal gesehen habe und ich eigentlich ganz glücklich bin, dass bisher alle Applikationen super laufen ("Wenn er schon mit APM nicht klar kommt, dann wird das ja mit Threads sicher besser funktionieren..."  ).
Auch dieses Programm läuft eigentlich prima, ich frage mich halt nur, warum die OnClick-Prozeduren die Kontrolle nicht bekommen, wenn ich erstmal in der Rechenschleife bin.
Da APM ja dafür sorgt, dass aufgelaufene Messages abgearbeitet werden (und dazu zählen eben auch Dinge wie Mausclicks oder Keypress), scheint das eigentlich kein schlechter Gedanke zu sein. Im Debugging Modus funktioniert alles planmäßig.
Der interessanteste Hinweis scheint mir der von Dunkel zu sein: "VCL-Zugriffe synchronisieren natürlich nicht vergessen." Was genau meinst Du damit?
P.S. Den Code hier reinzugeben bringt angesichts der Größe wenig. Aber prinzipiell sieht das Ding so aus:
Ursprünglich gab es eine simple Schleife:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| procedure loese_Aufgabe; begin while (b_s_1(Feld) > 0) do begin einzelschritt; anzeigen(Feld) end; end; |
...und die läuft unter Umständen etliche Minuten. Also habe ich das Ding erweitert.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure loese_Aufgabe; begin while (b_s_1(Feld) > 0) do begin einzelschritt; anzeigen(Feld); Application.ProcessMessages; if Abbr then exit; end; end; |
Die OnClick-Prozedur für den Abbruch-Button ist elementar einfach:
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TForm1.AbbruchClick(Sender: TObject); begin Form1.Memo1.Lines.Add('Abbruch'); Abbr:=true; end; |
Innerhalb von Einzelschritt wird übel rumgerechnet. An VCL-Aufrufen finden sich dort nur Form1.Memo1.Lines.Add um Meldungen über den Rechenstand rauszuhauen.
Anzeigen(Feld) enthält ein Befüllen eines StringsGrids Form1.StringGrid1.Cells[i,j]:=...
Mehr ist nicht.
Grüße Elrond
Moderiert von Gausi: Delphi-Tags hinzugefügt
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 16.10.08 16:06
mach mal break statt exit.
Un Ausserdem sin Globale Variablen böse!
Und wenns denn sein muss, solltest du die wohl auch hier posten!!!!
(Also am besten die ganze unit).
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 16:16
Hi,
Break statt Exit habe ich bereits ausprobiert und das mit der globalen Variablen (ich weiß, ich weiß) funktioniert prima, solange die Kontrolle an die OnClick-Prozedur geht.
Weißt Du was Dunkel mit "VCL-Aufrufe synchronisieren" meinte?
Grüße
Elrond
|
|
Jann1k
      
Beiträge: 866
Erhaltene Danke: 43
Win 7
TurboDelphi, Visual Studio 2010
|
Verfasst: Do 16.10.08 16:19
Die Schleife würde ich so machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| while (b_s_1(Feld) > 0) and (not abbr) do begin einzelschritt; anzeigen(Feld); Application.ProcessMessages; end; |
Außerdem sagst du das einzelscritt rechenintensiv ist, wenn einzelschrit der verzögernde Faktor ist, hilft dir das Konstrukt an dieser Stelle gar nichts.
Zuletzt bearbeitet von Jann1k am Do 16.10.08 16:20, insgesamt 2-mal bearbeitet
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 16.10.08 16:19
Du solltest jetzt auch mal den Kompletten Quelltext posten!!!!!!!!!!!!
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 16.10.08 16:20
VCL synchronisieren ist hier nicht nötig. Da du nur mit einem Thread (halt dem VCL-Hauptthread) arbeitest, ist das automatisch synchron, da die VCL nur zu sich selbst synchron arbeiten muss. Synchronschwimmen ohne Partner ist auch relativ einfach.
Wenn mam mit mehreren Threads arbeitet, muss man einige Sachen beachten, damit es nicht an allen Ecken knallt. hier ist das aber nicht nötig.
Wie wird denn die Prozedur loeseAufgabe aufgerufen? Normalerweise sollte das Konstrukt nämlich so funktionieren.
_________________ We are, we were and will not be.
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Do 16.10.08 16:36
Den Hinweis von Jann1k find ich auch nicht gerade unwichtig. Wenn diese Schleife nur 3 mal durchlaufen wird und die Methode einzelschritt aber 50 Sekunden rechnet, dann kann es so natürlich nicht funktionieren.
Wenn die Berechnung ohne Zugriffe auf das Formular/Komponenten auskommt (außer gelegentlichen Statusmeldungen), dann sind Threads absolut nicht schwer. Und das ist ja dann das Einzige was wirklich einen Sinn macht. Zu mal übermäßiges Aufrufen von ProcessMessages nur völlkommen unnötig ausbremmst und ProcessMessages durchaus den ein oder anderen Seiteneffekt auslösen kann.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 16:38
Ich hab's...ich hab's...
Innerhalb von anzeigen stand noch eine Leiche aus einem anderen Programm (copy+paste  ) und zwar ein Aufruf von
Form1.StringGrid1.SetFocus;
Ohne diesen Aufruf kann ich jetzt mit dem Abbruch-Button problemlos stoppen. Aber auch nur, wenn APM aufgerufen wird. Ohne APM klappt der Abbruch nicht.
Nur mal aus Interesse von einem Neuling: Warum verhindert SetFocus den Abbruch und warum brauche ich immer noch das (angeblich) so böse APM?
Grüße
Elrond
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 16.10.08 16:42
Naja, mit dem Setfocus kannst du nie den Button klicken, da der Focus sofort wieder auf das Stringgrid gesetzt wird!
Hättest du den Code hier gepostet, hätte dir das hier gleich jemand sagen können. Die Lösung mit Threads ist wohl trotzdem besser!
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 16:44
Jann1k hat folgendes geschrieben : | Die Schleife würde ich so machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| while (b_s_1(Feld) > 0) and (not abbr) do begin einzelschritt; anzeigen(Feld); Application.ProcessMessages; end; |
Außerdem sagst du das einzelscritt rechenintensiv ist, wenn einzelschrit der verzögernde Faktor ist, hilft dir das Konstrukt an dieser Stelle gar nichts. |
Mit der Schleife hast du natürlich recht. Ist eleganter als mit Break. Einzelschritt ist nicht das Problem sondern die Anzahl der Schleifendurchläufe in Kombination mit Einzelschritt. Insofern funktioniert das Ganze jetzt sehr gut.
Grüße
Elrond
|
|
Elrond 
      
Beiträge: 22
|
Verfasst: Do 16.10.08 16:47
Boldar hat folgendes geschrieben : | Naja, mit dem Setfocus kannst du nie den Button klicken, da der Focus sofort wieder auf das Stringgrid gesetzt wird!
|
Ergibt Sinn. Ich habe die Befehlsleiche einfach übesehen.
Grüße
Elrond
|
|