Methode nicht mehrmals gleichzeitig ausführen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Methode nicht mehrmals gleichzeitig ausführen

    Hallo,

    ich suche nach einer besseren Möglichkeit, herauszufinden, ob eine auszuführende Methode bereits ausgeführt wird. Der folgende Beispielcode soll es veranschaulichen:

    VB.NET-Quellcode

    1. Dim Ausfuehren As Boolean = True
    2. Public Sub Hauptformular_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Timer.Interval = 1000
    4. Timer.Start()
    5. End Sub
    6. Public Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
    7. MethodeAusfuehren()
    8. End Sub
    9. Public Sub MethodeAusfuehren()
    10. If Not Ausfuehren Then
    11. Exit Sub
    12. Else
    13. Ausfuehren = False
    14. End If
    15. '...
    16. Ausfuehren = True
    17. End Sub


    Derzeit bewerkstellige ich es mit der Hilfsvariablen "Ausfuehren". Gibt es eine elegantere Methode dafür?

    In meinem Programm wird so ähnlich eine Methode aufgerufen, die Punkte zeichnet. Das Programm wandelt eine Grafik in eine Punktgrafik um, um sie später auf einem Brailledrucker für Blinde ausdrucken zu können. Diese Grafik kann auch auf einem Brailledisplay angezeigt werden. Da die Reaktionszeiten des Displays leider etwas langsam sind, soll das Programm zwar in echtzeit laufen, aber der Grafikaufbau soll bei Bedarf übersprungen werden, damit es keine lange Warteschlange gibt. Leider gibt das Display keinen Wert zurück, wenn der Grafikaufbau abgeschlossen ist. Der Effekt soll so ähnlich sein, wie bei einem Spiel mit einer zu schwachen Grafikkarte. Es können Bilder übersprungen werden, aber am Ende soll immer die aktuellste Version angezeigt werden.

    Hat jemand eine Idee?

    Vielen Dank schon mal im Voraus.

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Wie soll es bei deinem Code vorkommen das dies geschieht? Läuft doch alles im selben Thread.

    Aber wenn du Multithreading anwendest, könnte das mit dem Flagge rauf und runter in die Hose gehen. Du kannst aber einen lock nutzen(SyncLock in VB), dann ist das auch ThreadSafe(wenn ich mich jetzt nicht irre).

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class Form1
    3. Private lockObject As Object = New Object()
    4. Private worker1 As Thread
    5. Private worker2 As Thread
    6. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    7. worker1 = New Thread(AddressOf Work1)
    8. worker2 = New Thread(AddressOf Work2)
    9. worker1.Start()
    10. worker2.Start()
    11. End Sub
    12. Private Sub Work1()
    13. For i As Integer = 0 To 9
    14. ExtendedWork1()
    15. Next
    16. End Sub
    17. Private Sub ExtendedWork1()
    18. SyncLock lockObject
    19. Debug.WriteLine("T1: " & Date.Now.ToString())
    20. Thread.Sleep(1000)
    21. End SyncLock
    22. End Sub
    23. Private Sub Work2()
    24. For i As Integer = 0 To 9
    25. ExtendedWork2()
    26. Next
    27. End Sub
    28. Private Sub ExtendedWork2()
    29. SyncLock lockObject
    30. Debug.WriteLine("T2: " & Date.Now.ToString())
    31. Thread.Sleep(1000)
    32. End SyncLock
    33. End Sub
    34. End Class


    Also schau mal bei MS in der Doku für weitere Details.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Du kannst es auch ggf. so probieren, dass Du beim Aufruf der Methode den Timer stoppst und am Ende ihn wieder aktivierst.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Das, mit dem Timer war nur ein Beispiel. In meinem Programm gibt es eine Funktion, die je nach Vergrößerungsfaktor, der X- und Y-Position die Arbeitsoberfläche in eine Picturebox zeichnet. Dabei werden auch die zu sehenden Braillepunkte gezeichnet. Aus dieser Methode heraus wird ein eine weitere Methode aufgerufen, die dann den entsprechenden Bereich der Arbeitsoberfläche für das Brailledisplay ermittelt, umrechnet und über eine Bluetoothschnittstelle and das Display weitergibt.

    Die Methode zur grafischen Darstellung wird u.a. jedesmal aufgerufen, wenn der Benutzer beispielsweise eine Cursortaste drückt, da dabei das Fokusrechteck, welches zum Setzen und Löschen von Braillepunkten dient verschoben wird.

    Durch die langsame Verarbeitung des Displays verzögert sich das Programm teilweise extrem. Ich möchte, dass, wenn das Display noch am Arbeiten ist, die Methode zum berechnen der Brailleausgabe übersprungen wird, sodas die Anzeige auf dem Display ruckeln kann, weil einige Schritte übersprungen werden.

    Ich habe mir die Definition von "SyncLock" angeschaut. Allerdings bin ich mir nicht sicher, ob diese Funktion mir nützt. Wenn ich beispielsweise einen Funktionsaufruf in ein SyncLock packe, wird dann die Funktion bei erneutem Aufruf nur übersprungen oder verschwindet sie in einer Warteschlange, um nachher noch ausgeführt zu werden. Für mein Programm wäre es gut, wenn ein SyncLock-Abschnitt übersprungen wird.
    Du kannst ja nicht feststellen, wann das Display das update durch hat. Das macht es schwierig was vernünftiges zu machen. Evtl. kann man das berechnen. Wenn das Display z.B. 1 Sekunde braucht um alle Pinne einmal umzuschalten, würde ich einfach nur 1 mal pro Sekunde zum Display senden, wenn denn was zum senden da ist.

    Der Timer tickt dann regelmäßig, wenn der Buffer nicht nothing ist wird gesendet, nach dem senden den buffer wieder löschen. Ich denke das ist so auch schonender für das Display, weil dann ingesammt weniger updates gemacht werden. So sendest du dann immer nur die aktuellen Daten und dein Programm sollte flüssig laufen.

    Wenn das so keine Option für dich ist, können wir weiter überlegen. Dann müsste ich aber wissen, ob du Async oder Multithreading anwendest.


    VB.NET-Quellcode

    1. Public Class Form1
    2. Private ticker As New Timer With {.Interval = 1000, .Enabled = True}
    3. Private buffer As Byte()
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. AddHandler ticker.Tick, AddressOf tickerTick
    6. End Sub
    7. Private Sub tickerTick(sender As Object, e As EventArgs)
    8. If Not buffer Is Nothing Then
    9. 'senden
    10. buffer = Nothing
    11. End If
    12. End Sub
    13. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    14. buffer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    15. End Sub
    16. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    17. buffer = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    18. End Sub
    19. End Class

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    ich habe mir ein BusyDelay gebastelt, dem ich eine Methode übergeben kann. Die Methode wird dann verzögert aufgerufen, nämlich im Application_Idle - Event.
    Das ist ein Event was feuert, bevor die Anwendung in die Warteschleife zurückfällt, wo sie auf BenutzerEingaben wartet.
    Wenn schnell hintereinander Methoden ins BusyDelay gegeben werden - während die App noch Sachen abarbeitet, so wird nur die als letzte eingegebene Methode ausgeführt - Prinzip "Last-in-wins".
    Ich benutze das zB gerne, wenn auf MouseMove zu reagieren ist, weil Mouse-Moves werden u.U. sehr schnell hintereinander gefeuert.
    Interesse?
    Danke für die Idee, aber das ist noch etwas komplizierter.

    Also:

    Es gibt sogenannte Braillezeilen, die von einem Screenreader angesprochen werden. Das, was der Screenreader im Fokus hat, wird auch auf die Braillezeile übertragen. Damit kann eine blinde Person an einem PC arbeiten. Eines meiner Ziele ist es, dass Blinde mit diesem Programm selbständig Braillegrafiken erstellen und bearbeiten können sollen. Mit einer angeschlossenen Braillezeile funktioniert alles hervorragend, da diese weniger Stifte haben und auch schneller reagieren. Meine Braillezeile hat beispielsweise 80x8 Stifte. Das Brailledisplay hat 48x76 Stifte. Die Technik darin scheint etwas älter zu sein. Ich habe nun ein Modul geschrieben, welches, wie bei einem Zeichentrickfilm mehrere Bilder als Animation abspielen kann, sodas Bewegungsabläufe und Perspektiven für Blinde besser veranschaulicht werden können. Auf diese Weise kann eine blinde Person Dinge erfassen, die er sonst nie erfahren könnte, wie z.B. ein galopierendes Pferd oder auch die Veränderung eines Schattens, den ein Baum wirft, wenn die Sonne über den Himmel wandert.

    Sorry für den Roman, aber vielleicht konnte ich einiges verdeutlichen.
    Also ich weiss jetzt nicht, was nun die genaue Anforderung ist - ich fass mal zusammen:
    Es gibt schnelle Abfolgen von Zuständen.
    Es gibt eine Braille-Zeile, mit wenigen Stiften, die da hinterherkommt.
    Und es gibt ein Braille-Display, mit vielen Stiften, was da nicht mehr mitkommt, und dassis das Problem.

    Was soll nun passieren mit dem Display, wenn eine solch schnelle Abfolge auftritt?
    Ich sehe da zwei Möglichkeiten:
    1. Für das Display wird der Ablauf verlangsamt
    2. Beim Display werden Zwischen-Zustände darzustellen ausgelassen.
    Was ist dein Plan?
    Mein Plan ist Punkt 2. Es können Swischenschritte ausgelassen werden, sodass ein gewisses Ruckeln entsteht. Am Ende der Prozedur soll aber die aktuelle Grafik angezeigt werden. Daher ist "SyncLock" eine gute Idee, wenn der entsprechende Bereich bei mehrmaligem Aufruf nur übersprungen wird und nicht noch nachträglich ausgeführt wird.
    Mein Vorschalg mit dem Timer ist sehr leicht umsetzbar. Dazu kannst du auch eine TrackBar nutzen, so das der User selbst die Updategeschwindigkeit der Zeilen/Displays einstellen kann. Wenn bei dir bei 2 Modellen solche unterschiede Vorhanden sind, wird das auch bei deinen Usern so einige Unterschiede geben, von Schildköten bis zu Geparden was die Geschwindigkeit angeht, daher denke ich das das durchaus Sinn machen kann.

    Aber schau dir an was der ErfinderDesRades noch sagen wird, ich wäre fast bereit zu wetten, das er noch mit einer brillanten Idee um die Ecke kommt.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    nö, was neues ausser dem BusyDelay habich nicht.
    nur soviel, dass es sich verhält wie ein maximal hochgetakter Timer. Weil beim Timer ists genauso: Während die CPU mit dem Display beschäftigt ist, kann der Timer halt nicht ticken.

    Allerdings ist noch anzumerken, dass "SyncLock" garnichts zum Problem beitragen kann - da würdeste dich nur gemein verzetteln.
    Ja Synclock wird hier nichts nutzen, ich denke das Problem ist einfach das der Sendevoorgang schneller von statten geht, als das Update des Displays selbst. Deshalb denke ich das das IDLE-Event möglicherweise auch nichts bringt.

    Ich kenne das auch von MCUs(Mikrokontrollern), die Daten sind ratz fatz gesendet, passiert aber auf der MCU nach dem Lesevorgang weiteres, kann die MCU solange nicht lesen(ausser man hat das entsprechend programmiert und auf der MCU wird der Vorgang abgebrochen, wenn Daten zum lesen da sind, das muss man dann aber auch ständig prüfen), will man aber in dem Moment in der PC-Anwendung senden, kann erst geschrieben werden, wenn die MCU lesen kann, solange ist der Thread dann blockiert. Und das könnte das Problem von tron25 sein, falls er alles im UI Thread macht. Bisher wurde uns ja nicht gesagt ob Async oder Threads im Spiel sind. Da tron sagte, das seine App "verzögert" wird, halte ich das für sehr wahrscheinlich.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Der entsprechende Code ist nicht in Threads und wird auch nicht async aufgerufen. Kann mir jemand von euch sagen, ob ein SyncLock-Abschnitt bei mehrmaligem Aufrufen übersprungen oder in eine Warteschlange geschoben wird. Wenn der Abschnitt übersprungen wird, wäre das genau das, was ich suche.
    Nein, wie du dir das vorstellst wird das nichts. Dein Problem ist auch ein anderes, genau das habe ich im meinem letzten Post beschrieben. Deine Geräte sind einfach nicht bereit zu lesen wenn sie noch am Updaten sind, solange das Gerät updated kann deine App nicht senden, will aber und muss warten(Thread blockiert) bis ein Timeout erreicht wird oder die Geräte lesen können, dadurch wird deine App ruckelig.

    Um das anständig zu verbessern, bleibt nur Async oder Threading, wobei dann immer nur die aktuellen Daten geschrieben werden sollten. Im UI-Thread kannst du ruhig die Daten zum senden erstellen, aber das schreiben muss Async oder in einem anderen Thread passieren. Wenn du aber einfach einen Timer + Trackbar nimmst, kannst du den Intervall so anpassen, das nur geschrieben wird, wenn das Display sicher mit dem Update durch ist, dadurch verhinderst du das ruckeln in deiner App, weil dann bei jedem schreibvorgang deine Geräte im IDLE sind und lesen können und es keinen blockiert UI-Thread gibt, sofern der Interval gut eingestellt ist.

    Ich würde einfach Async oder Threading einbauen, wie gesagt im UI-Thread die Daten preparieren, und einfach nebenläufig immer senden. Wenn der andere Thread warten muss bis er schreiben kann, macht das nichts aus.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    Nein, das Programm selbst ruckelt nicht. Ich kann beispielsweise mit einem Finger auf dem Display zeichnen. Auf meinem Bildschirm sehe ich die Zeichnung fast in Echtzeit. Allerdings dauert es recht lang, bis die entsprechenden Punkte auch auf dem Brailledisplay erscheinen.

    Das Display hat 78 Zeilen und erwartet 13 Datensätze. Also, jeder Block besteht aus 48 Punkten und 6 Zeilen. Nun habe ich den entsprechenden Code so angepaßt, dass festgestellt wird, in welchem Block sich etwas seit dem letzten mal geändert hat, sodas nur die Blöcke übertragen werden, die eine Veränderung beinhalten. Dadurch dürfte sich die Reaktionszeit auch etwas verkürzen. Leider ist das Brailledisplay auf meiner Arbeit und ich bin heute im Homeoffice. Am Dienstag werde ich die Änderungen ausprobieren.

    Soweit ich informiert bin, werden bei "Async" die Await-Abschnitte nachgeholt, bzw. die aufrufende Methode wartet nicht ab. Ich versuche es mal anders zu beschreiben:

    Bildschirminhalt wird aufgebaut
    Brailleausgabe wird erstellt
    Bildschirminhalt wird erneut aufgebaut
    Da die Brailleausgabe noch nicht abgeschlossen ist, wird sie einfach übersprungen
    Bildschirminhalt wird ein weiteres mal aufgebaut
    Brailleausgabe ist beendet und kann daher erneut ausgeführt werden, ohne den vorherigen Versuch nachzuholen

    Wird ein SyncLock-Abschnitt nachgeholt, wenn er beim letzten Versuch gesperrt war?

    tron25 schrieb:

    Wird ein SyncLock-Abschnitt nachgeholt, wenn er beim letzten Versuch gesperrt war?


    tron25 schrieb:

    Ich habe mir die Definition von "SyncLock" angeschaut. Allerdings bin ich mir nicht sicher, ob diese Funktion mir nützt.


    Aha, hast du aber nicht wirklich verinnerlicht, sonst wüsstest du das. Ich denke du hast mein Beispiel entweder nicht oder nicht richtig getestet, denn die Debug-Ausgabe hätte das deutlich gemacht.
    Nun haben dir hier 2 Leute gesagt, SyncLock ist hier nicht das richtige, ich hatte es zwar erst empfohlen, hatte aber nicht genug Hintergrund. Daher das Beispiel mit dem Synclock, was du nun am besten ganz weit weg legst.

    tron25 schrieb:

    Durch die langsame Verarbeitung des Displays verzögert sich das Programm teilweise extrem. Ich möchte, dass, wenn das Display noch am Arbeiten ist, die Methode zum berechnen der Brailleausgabe übersprungen wird, sodas die Anzeige auf dem Display ruckeln kann, weil einige Schritte übersprungen werden.


    Du kannst nicht feststellen, wann das Display noch arbeitet hast du gesagt. Wie soll dann wärend dieser Zeit übersrpungen werden, wenn du diesen Zeitraum nicht kennst?(Nur die Zeitpunkt wann es losgeht, also nachdem senden) Ich bin nun nur noch verwirrt. Ich glaube ich kann dir nicht helfen, da du alles im UI-Thread machst, mach es mit dem Boolean, wie auch immer du feststellen willst wann das Display fertig ist.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Es gab wohl einige Mißverständnisse bzw. habe ich mich etwas undeutlich ausgedrückt. Also:
    Das Programm läuft normal schnell. Das Brailledisplay bekommt seine Anweisungen und kommt mit dem Aufbauen der Grafik nicht hinterher und braucht daher etwas länger. Die Idee mit dem Timer schein gut zu sein. Dieser soll dann jedesmal eine Methode aufrufen, die den Inhalt der Punkttabelle an das Display sendet. Wenn das Programm innerhalb eines Intervalls mehrmals die Tabelle aktualisiert, wird durch den Timer immer nur die aktuellste an das Display gesendet.

    Außerdem habe ich nochmal im Netz nach "SyncLock" geschaut und festgestellt, dass ihr recht habt. Der entsprechende Abschgnitt wird für andere Threads gesperrt und nachgeholt, senn der Bereich wieder freigegeben ist.

    Vielen Dank nochmal für eure Hilfe und eure Geduld und ein schönes verlängertes Wochenende.
    Wenn das Display nicht mehr hinterherkommt, sende weniger. So einfach ist das, das was du da machen willst, wäre wie wenn du beim spielen V-Sync aus hast und es zum tearing kommt, also ein fehlerhaftes Bild. Wenn du Animationen darstellen willst, würden deine User keine echte darstellung ertasten. Frame vorbereiten, Frame Anzeigen, das ist der Weg. Wenn die Geräte nicht schneller können, verfälscht du so nur deine Animation.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    So, jetzt habe ich es getestet. Durch die Blockweise Übersetzung laufen Animationen deutlich flüssiger. Je mehr Blöcke übersetzt werden sollen, desto mehr sieht es aus, wie früher, aber für die meisten Abläufe bringt diese Methode einen großen Vorteil.

    Vielen Dank für eure Tipps unbd Hilfe.