vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Schützen Sie Ihre Software vor Software-Piraterie - mit sevLock 1.0 DLL!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück

 Sie sind aktuell nicht angemeldet.Funktionen: Einloggen  |  Neu registrieren  |  Suchen

Fortgeschrittene Programmierung
Stack abbrechen 
Autor: quickmic
Datum: 20.11.07 12:33

Hi Leute

Ich versuche seit gestern ein besch... Problem in den Griff zu bekommen. Ich habe eine Routine (im original einige Datenbank-Operationen), die relativ Zeitaufwendig sein können. Diesen Code möchte ich bei einem Wiederholungsfall (Stack oder??) abbrechen.
Zur Simulation verwende ich diesen Code:

Option Explicit
Private CancelFlag As Boolean
Private RunnningFlag As Boolean
Private Sub Command1_Click()
    Label1 = vbNullString
 
    If RunnningFlag Then
        CancelFlag = True
 
        While RunnningFlag
            DoEvents
        Wend
    End If
 
    Call Stacktest
End Sub
Private Sub Stacktest()
    Dim i As Long
 
    RunnningFlag = True
 
    For i = 0 To 100000
        Label1 = Str(Val(Label1) + 1)
 
        DoEvents
 
        If CancelFlag Then
            CancelFlag = False
            Exit For
        End If
    Next
 
    RunnningFlag = False
End Sub
Wie man daraus ersehen kann, soll das Sub "Stacktest" abgebrochen werden und neu gestartet, wenn man erneut den Button drückt.
Leider klappt das nicht, da VB im....

While RunnningFlag
      DoEvents
Wend
... hängen bleibt.
Ich hab auch schon mit Klassenmodulen getestet . Sowohl normal als auch versucht ein "dynamischen Klassenmodul-Array" zu machen, und das 1.Modul dann "wegzudimensionieren". Das hat dann solala geklappt.... Auch nicht das was ich wollte.
Ebenfalls hab ich's per Classenmodul und "Events" probiert....Wieder Fehlanzeige

Das einzige was geht ist das Teil per Timer zu "entkoppeln".
Das hat aber den Nachteil, dass dann nichtmehr "gewartet" wird, bis der Code beendet ist.

Ich hoffe jemand von euch kann mir bei dem Prob. helfen. Im Mom weiss ich ncihtmehr weiter...

mfg
quickmic
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: Dirk
Datum: 20.11.07 13:47

Ich denke, der Aufruf Call Stacktest müsste im Else vom If Running sein. Sonst startet er ja gleich wieder StackTest. Egal ob du abbrichst oder nicht. Evtl. hast du hier das Problem, dass StackTest mehrmals (reentrant) aufgerufen wird. D.h. StackTest ist noch nicht fertig, du rufst es aber schon wieder auf.

Private Sub Command1_Click()
    Label1 = vbNullString
 
    If RunnningFlag Then
        CancelFlag = True
 
'        While RunnningFlag Ist das nötig??
'            DoEvents
'        Wend
    Else
       Call Stacktest
    End If
 
End Sub
Falls das völlig daneben ist, verstehe ich deine Anforderungen nicht richtig.

Gruß
Dirk

--
?Get it right the first time

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: quickmic
Datum: 20.11.07 14:01

Genau das ist mein Problem, dass der "Stacktest" mehrmals hintereinander aufgerufen wird (bzw. sein kann). In dem Fall soll der 1.Thread/Stack/Instanz (wie auch immer) abgebrochen werden.

Also genau das:
"...hast du hier das Problem, dass StackTest mehrmals (reentrant) aufgerufen wird"

ABER, das ist nicht mein Problem, sondern genau so beabsichtigt. Das Problem liegt nur darin, dass ich eben den 1. Durchlauf nicht vom 2.Durchlauf aus unterbrechen kann.

Der Bsp. Code ist also schon richtig.
Das "If RunnningFlag Then" kann ja nur gesetzt sein, wenn durch die 1. Instanz noch am laufen ist. Dann wird das CancelFlag gesetzt, und sollte die 1.Instanz korrekt beenden (was es nicht tut, weil VB im Doevents hängt). Dannach soll dann erneut der Stacktest gestartet werden.



Nur um den Sinn darin zu sehen....
Ich hab einige Filter-Auswahlfelder für eine DB die per Klicken auf ein Flexgrid ausgeführt werden. Da meine DB aber ca 100000 Einträge hat, kann das schonmal 4-5Sek dauern. Jetzt will ich aber nicht Alles für die Dauer des Ausführens sperren, sondern es soll zwischenzeitlich eine andere Auswahl getroffen werden können, die die 1.Instanz (vielleicht falsch (Verklickt bei der Auswahl)) abbrechen soll.


mfg
quickmic
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: Zardoz
Datum: 21.11.07 00:15

Hi quickmic,
probiers mal so:
Option Explicit
 
Private CancelFlag As Boolean
Private RunnningFlag As Boolean, flgNeustart As Boolean
 
Private Sub Form_Load()
  flgNeustart = False
  CancelFlag = False
  RunnningFlag = False
End Sub
 
Private Sub Command1_Click()
' Starten
  Label1.Caption = ""
  If RunnningFlag = False Then
    Call StackTest
  Else
    flgNeustart = True
    CancelFlag = True
  End If
End Sub
 
Private Sub Command2_Click()
' Abbruch
  flgNeustart = False
  CancelFlag = True
End Sub
 
Private Sub StackTest()
 
  Dim i As Long
 
  RunnningFlag = True
  Do
    flgNeustart = False
    For i = 0 To 100000
      Label1.Caption = Str$(i)
      DoEvents
      If CancelFlag = True Then
        CancelFlag = False
        Exit For
      End If
    Next i
  Loop While flgNeustart = True
  RunnningFlag = False
End Sub

Gruss,

Zardoz

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: quickmic
Datum: 21.11.07 08:20

Danke für die Hilfe. Etwas Ähnliches in diese Richtung hab ich ebenfalls schonmal getestet allerdings mit einem Timer. Das System hat aber leider einen Haken:

Beim 1.Mal starten wird im Sub "Command1_Click" gewartet bis "StackTest" fertig durchlaufen ist und dann beendet. So soll es auch sein.

Beim 2.Mal aber wird "Command1_Click" sofort durchlaufen, ohne auf "StackTest" zu warten.

Das ist in dem Bsp nicht schlimm, aber in meinem Fall kommt dannach noch Einiges an Code, welcher erst NACH dem fertigen Durchlaufen des "StackTest" ausgeführt werden darf.

Private Sub Command1_Click()
' Starten
  Label1.Caption = ""
  If RunnningFlag = False Then
    Call StackTest
  Else
    flgNeustart = True
    CancelFlag = True
  End If
  MsgBox "Hier muss alles fertig sein, denn hier steht noch viel Code"
End Sub
Also müsste an der Stelle der Msgbox-Codezeile wieder irgendeine "Warteroutine" rein. z.b.

Private Sub Command1_Click()
' Starten
  Label1.Caption = ""
  If RunnningFlag = False Then
    Call StackTest
  Else
    flgNeustart = True
    CancelFlag = True
  End If
  Do While RunningFlag
    DoEvents
  Loop
  MsgBox "Hier muss alles fertig sein, denn hier steht noch viel Code"
End Sub
....und das Resultat ist das selbe wie bei meinem ersten Bsp. VB "hängt" im Doevents.

mfg
quickmic
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: Dirk
Datum: 21.11.07 11:17

DoEvents ist dafür da, die Kontrolle ans Betriebssystem zurück zu geben, um asynchrone Ereignisse wie Maus- und TastaturEvents zu verarbeiten. Wenn dein StackTest noch nicht zu Ende gelaufen ist und du "mittendrin" in deine Button Ereignisprozedur springst, ist damit StackTest unterbrochen und wird erst wieder weiterlaufen, nachdem Command1_Click fertig ist. Das wird aber niemals fertig, da StackTest nicht in der Lage ist - weil unterbrochen - das RunningFlag auf False zu setzen.

Entweder beschäftigst du dich mit Threads oder du änderst dein Design.
Packe mal folgende Zeilen in deinen Button-Handler und die Funktion TestStack
  Static Indent As Integer
  Indent = Indent + 1
 
  Debug.Print String(c_IND * Indent, ">") & " Command1_Click" 'bzw. testStack
 
  'Hier kommt der Code
 
  Debug.Print String(c_IND * Indent, "<") & " Command1_Click"
 
  Indent = Indent - 1
Hier kannst du sehr gut die Aufruf-Hierachie an den Printouts nachvollziehen. Du wirst also feststellen, das der Aufruf von TestStack synchrin erfolgt, dass heißt, du kommst erst in deinen Button-Handler zurück, wenn TestStack fertig ist. Der wird aber nicht fertig, weil du die while-loop im zweiten Aufruf von Command1_Click nudelt.

Ich stelle mir daher folgende Lösung vor:

Option Explicit
 
Private Const c_IND As Integer = 3
 
Private m_Break As Boolean
Private m_NeuAuftrag As Boolean
Private m_IsAuftragRunning As Boolean
Private m_CloseApp As Boolean
 
Private Sub Command1_Click()
 
 
  Static Indent As Integer
  Indent = Indent + 1
 
  Debug.Print String(c_IND * Indent, ">") & " Command1_Click"
 
  If m_IsAuftragRunning Then
    m_Break = True
    m_NeuAuftrag = True
  End If
  Timer.Interval = 1
  Timer.Enabled = True
 
  Debug.Print String(c_IND * Indent, "<") & " Command1_Click"
 
  Indent = Indent - 1
 
End Sub
 
 
Private Sub test()
 
  Dim i As Long
 
  Static Indent As Integer
  Indent = Indent + 1
 
  Debug.Print String(c_IND * Indent, ">") & " test"
 
  For i = 1 To 1000000
 
    If i Mod 10 = 0 Then
      If m_Break Then
        Debug.Print String(c_IND * (Indent + 1), ".") & " BREAK-->"
        Exit For
      End If
      Label1.Caption = CStr(i)
      DoEvents
    End If
 
  Next i
  If Not m_Break Then Debug.Print String(c_IND * (Indent + 1), ".") & " MADE IT" & _
    "!!!"
 
  Debug.Print String(c_IND * Indent, "<") & " test"
 
  Indent = Indent - 1
 
End Sub
 
Private Sub Form_Load()
 
  m_Break = False
  Timer.Interval = 1
  Timer.Enabled = False
  m_NeuAuftrag = False
  m_IsAuftragRunning = False
  m_CloseApp = False
 
End Sub
 
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
 
  m_Break = True
  m_NeuAuftrag = False
  m_CloseApp = True
 
  If m_IsAuftragRunning Then
    Cancel = 1
  End If
 
End Sub
 
Private Sub Timer_Timer()
 
  Static Indent As Integer
  Indent = Indent + 1
 
  Debug.Print String(c_IND * Indent, ">") & " Timer_Timer"
 
  Timer.Interval = 500
 
  If m_IsAuftragRunning Then
    Timer.Enabled = False
  Else
    m_IsAuftragRunning = True
    test
    m_IsAuftragRunning = False
    If m_CloseApp Then
      SendKeys "%{F4}", False
      DoEvents
    End If
    If m_NeuAuftrag And m_Break Then
      m_NeuAuftrag = False
      Timer.Enabled = True
    Else
      Timer.Enabled = False
    End If
    m_Break = False
  End If
 
  Debug.Print String(c_IND * Indent, "<") & " Timer_Timer"
 
  Indent = Indent - 1
 
End Sub
Bei mir scheint's zumindest zu funktionieren. Jetzt schreibst du, dass da irgendwo noch ganz viel Code kommt. Grundsätzlich ungünstig viel Code in einer Ereignisprozedur zu haben. Besser auslagern in eine Sub/Funktion. Du kannst ja nun noch ein Flag setzen, dass TestStack oder hier test es gemacht hat und dann entsprechend den Code ablaufen lassen.

Ich denke ohne Timer kriegste das nicht hin. Denn du willst ja so eine Art Threading erreichen. App beenden bzw. Form schließen habe ich noch extra verarbeitet.

Gruß
Dirk

--
?Get it right the first time

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Stack abbrechen 
Autor: quickmic
Datum: 21.11.07 12:26

"DoEvents ist dafür da, die Kontrolle ans Betriebssystem zurück zu geben, um asynchrone Ereignisse wie Maus- und TastaturEvents zu verarbeiten" ... Leuchtet ein. Darum geht auch die Timer-Methode, weil das Timer-Event vom OS kommt.

Dein Bsp klappt auch bei mir, aber eben leider genau wie ich es nicht brauchen kann.
Warum das ganze mit dem Doevents nicht klappen kann, ist mir nun auch klar. Sowas in die Richtung hab ich ja bereits vermutet.

Leider bin ich jetzt etwas ratlos...
Du meinst entweder Code (Timer) ändern, oder Threads machen.

"Besser auslagern in eine Sub/Funktion. Du kannst ja nun noch ein Flag setzen, dass TestStack oder hier test es gemacht hat und dann entsprechend den Code ablaufen lassen."

Der Code steht natürlich bereits in einer Sub/Function drin, aber er wird von mehreren Stellen im Code und immer wieder in etwas modifizierter Form, benötigt. Ich kann da also keinen Timer einbauen, der mir nach Schema F den 2.Teil des Codes ausführt.
Ausserdem wird das ganze dann unglaublich unübersichtlich und hässlich.
z.b.

Einmal benötige ich einen Stack bei den SQL-Kommandos-Unterprogramm (Da sind dann die Auswahlfilter drin). Das kann z.b. mehrere Sek dauern bis die Recordsets geladen sind, und 2. Beim Füllen des Flexgrids, was wieder einige Sek dauern kann.
Ich kann daher eigentlich die Timer-Methode schon nahezu ausschliessen.
Bleibt also noch die Methode mit den Threads.

Leider erinnere ich mich mit Grauen an den letzten Versuch mit VB Threads hinzubekommen. Diese Methode möchte ich daher nur im Absoluten Notfall einsetzen.

Ich möchte aber nochmal vielleicht auf die Klassenmodul-Methode zurückkommen, die ich am Anfang kurz erwähnt hab.
Vielleicht ist ja mit diesem Weg mehr anzufangen, zumindest hatte ich bis jetzt den "grössten" Erfolg mit diesem Code:

Im Form1:

Option Explicit
Private class1() As class1
Private counter As Integer
 
Private Sub Command1_Click()
    If (Not Not class1) <> 0 Then 'Array dimensioniert?
        class1(0).cancel
        Set class1(0) = Nothing
        Erase class1
        ReDim class1(0)
        Set class1(0) = New class1
        class1(0).Stacktest
    Else
        ReDim class1(0)
        Set class1(0) = New class1
        class1(0).Stacktest
        Set class1(0) = Nothing
        Erase class1
    End If
 
    MsgBox "Durchlauf fertig"
End Sub
Im Class1:

Option Explicit
Private cancelflag As Boolean
Private RunnningFlag As Boolean
Public Sub cancel()
    cancelflag = True
End Sub
 
Public Sub Stacktest()
    Dim i As Long
 
    RunnningFlag = True
 
    For i = 0 To 10000
        Form1.Label1 = Str(i)
 
        DoEvents
 
        If cancelflag Then
            cancelflag = False
            Exit For
        End If
    Next
 
    RunnningFlag = False
End Sub
Das Problem hier ist, dass zwar "Stacktest" im Klassenmodul abgebrochen (ich würde eher sagen abgewürgt) wird, aber das 1.Button-Event nicht sofort beim abwürgen beendet wird.
Kann man da noch was optimieren, oder bleibt wirklich nur der Weg mit den Threads?

mfg
quickmic
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Sie sind nicht angemeldet!
Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.

Einloggen  |  Neu registrieren

Funktionen:  Zum Thema  |  GesamtübersichtSuchen 

nach obenzurück
 
   

Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel