Lebensbit überwachen

  • VB.NET

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von shad.

    Lebensbit überwachen

    Hallo,

    ich stehe gerade auf dem Schlauch...
    In meinem Programm habe ich ein Signal vom Typ Bool, das ständig zwischen 0/1 wechselt. Es ist eine Art Überlebensbit.
    Wie kann ich diese Bit überwachen, so dass es mir nach ich sage mal 10 Sekunden einen Fehler ausgibt, sobald kein Signalwechsel mehr stattfindet?

    Ich habe ein paar Timer-Varianten probiert, jedoch ohne Erfolg.

    VB.NET-Quellcode

    1. Dim IsAlive As Boolean = True

    Im Timer:

    VB.NET-Quellcode

    1. If Not IsAlive Then MessageBox.Show("Is Not Alive")
    2. IsAlive=False

    Da wo das Signal gesetzt wird:

    VB.NET-Quellcode

    1. Property Signal As Boolean
    2. Get
    3. Return Signal_
    4. End Get
    5. Set (value As Boolean)
    6. If Value <> Signal_ Then IsAlive = True
    7. Signal_ = value
    8. End Set
    9. End Property
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    @petaod Nicht ganz.
    @Murdersquad In der Bit-Change-Property startest Du den 10-Sekunden-Timer neu, wenn das Signal geändert wird.
    Im Timer-Tick-Event meldest Du das Ausbleiben des Signals:

    VB.NET-Quellcode

    1. Property Signal As Boolean
    2. Get
    3. Return Signal_
    4. End Get
    5. Set (value As Boolean)
    6. If Value <> Signal_ Then Timer1.Start()
    7. Signal_ = value
    8. End Set
    9. End Property
    10. Sub Timer1_Tick()
    11. MessageBox.Show("Is Not Alive")
    12. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Extra Event klingt gut. Ggf. noch mit einem Async/Await+Task.Delay+CancellationTokenSource kombinieren, dann spart man sich die Timer-Komponente und man kann alles sauber innerhalb einer Klasse kapseln.
    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.

    petaod schrieb:

    um die Überwachung zu aktivieren
    Das muss natürlich mit dem Start der Kommunikation überhaupt beginnen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich hatte mich in der Vergangenheit ja schon mal mit diesen einfachen Properties beschäftigt, aber verstehen tue ich sie noch immer nicht vollumfänglich. Wahrscheinlich muss ich es an einem funktionierenden Beispiel testen.

    Wieso gibt es einmal das Bit "Signal" und dann "Signal_"? Muss ich "Signal_ " noch irgendwo deklarieren?
    Wenn man Set (value as Boolean) schreibt, ist "value" dann automatisch schon auf True?

    VB.NET-Quellcode

    1. Property Signal As Boolean
    2. Get
    3. Return Signal_
    4. End Get
    5. Set (value As Boolean)
    6. If Value <> Signal_ Then Timer1.Start()
    7. Signal_ = value
    8. End Set
    9. End Property
    10. Sub Timer1_Tick()
    11. MessageBox.Show("Is Not Alive")
    12. End Sub



    Tut mir leid für die blöden Fragen :/
    @Murdersquad Das ist eine Property, die im Setter separaten Code ausführt.
    Wäre dies nicht der Fall, würde die Zeile

    VB.NET-Quellcode

    1. Property Signal As Boolean
    genügen.
    Ja, Signal_ muss separat deklariert werden:

    VB.NET-Quellcode

    1. Private Signal_ As Boolean

    Signal eine Property mit der beigeordneten Variable Signal_,
    Nicht initialisierte VAriablen stehen in .NET immer auf einem Null-Wert, bei einem Boolean wäre das False.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Murdersquad schrieb:

    Wenn man Set (value as Boolean) schreibt, ist "value" dann automatisch schon auf True?
    Nein, der Wert von Value wird durch die Verwendung in Deinem Programm festgelegt.

    VB.NET-Quellcode

    1. Dim Testinstanz As New DeinObjekt
    2. Testinstanz.Signal = True

    Signal ist Deine Property. Sobald Du der einen Wert zuweist (Testinstanz.Signal = NeuerWert), wird der Property-Setter (also Set(value As Boolean)) aufgerufen, wobei value den Wert von NeuerWert, also in dem o.g. Codeblock True hat. Sobald Du den Wert von Signal abfragst, wird der Property-Getter, also die Get-Prozedur aufgerufen und der Wert von Signal_ zurückgegeben:

    VB.NET-Quellcode

    1. Dim x = Testinstanz.Signal

    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.
    Ein Timer ist gar nicht nötig.

    Hier eine kleine Simulation. Es ist zwar ein Timer dabei, der ist jedoch nur für den Wechsel von LiveBit zuständig.

    EDIT: Ja das stimmt. Ist aber mit einer einfachen Sleep-Statement schon gelöst.
    Aus der Schleife muss er sowieso, da er an die Zeit gebunden ist.

    Freundliche Grüsse

    exc-jdbi

    Einfach nur Enter drücken und warten
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Timers
    4. Public Module TestLiveBit
    5. Private MLiveBit As Int32
    6. Private Start As DateTime
    7. Private StopAfter As Int32
    8. Private Rand As New Random
    9. Private WithEvents Timer1 As New Timer
    10. Private Property LiveBit As Int32
    11. Get
    12. Return MLiveBit
    13. End Get
    14. Set(value As Int32)
    15. If DateTime.Now.Subtract(Start).Seconds <= StopAfter Then
    16. Start = DateTime.Now
    17. MLiveBit = value
    18. End If
    19. End Set
    20. End Property
    21. Public Sub Main()
    22. StopAfter = 5
    23. 'Startet den Timer der das LiveBit-Signal simuliert
    24. Dim s = "Press 'Enter' for stop LiveBit. Stop after {0}s."
    25. Console.WriteLine(s, StopAfter) : Console.WriteLine()
    26. TimerStart(True)
    27. Start = DateTime.Now
    28. Console.ReadLine()
    29. Console.WriteLine()
    30. Console.WriteLine("Wait .... {0}s", StopAfter)
    31. TimerStart(False)
    32. While True
    33. Threading.Thread.Sleep(1)
    34. If DateTime.Now.Subtract(Start).Seconds > StopAfter Then
    35. Exit Sub
    36. End If
    37. End While
    38. End Sub
    39. Private Sub TimerStart(_start As Boolean)
    40. If _start Then
    41. Timer1 = New Timer With {
    42. .Enabled = True,
    43. .Interval = 20
    44. }
    45. Timer1.Start()
    46. Return
    47. End If
    48. Timer1.Stop()
    49. Timer1.Enabled = False
    50. Timer1 = Nothing
    51. End Sub
    52. Private Sub Timer1_Tick(sender As Object, e As ElapsedEventArgs) Handles Timer1.Elapsed
    53. 'Der Timer wird nur gebrauch um das LiveBit-Signal zu simulieren
    54. LiveBit = Rand.Next(2)
    55. Console.Write(MLiveBit)
    56. End Sub
    57. End Module

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    exc-jdbi schrieb:

    Es ist zwar ein Timer dabei, der ist jedoch nur für den Wechsel von LiveBit zuständig.
    Dafür läuft die Warte-Logik als CPU-fressende Endlosschleife im Haupt-Thread und blockiert alles restliche Tun.
    Das ist keine so gute Idee.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    exc-jdbi schrieb:

    VB.NET-Quellcode

    1. While True
    2. If DateTime.Now.Subtract(Start).Seconds > StopAfter Then
    3. Exit Sub
    4. End If
    5. End While
    Eine Endlosschleife in diesem Kontext ist ja wohl ein NoGo. :thumbdown:
    @petaod war schneller.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Auch wenn Overkill, fasse ich mal Post#5 (von @FormFollowsFunction) und #6 zusammen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class FrmMain
    2. Private WithEvents TestInstance As New TestClass
    3. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. End Sub
    5. Private Sub BtnToggleAliveStatus_Click(sender As Object, e As EventArgs) Handles BtnToggleAliveStatus.Click
    6. TestInstance.Signal = Not TestInstance.Signal
    7. LblAliveStatus.Text = TestInstance.Signal.ToString
    8. End Sub
    9. Private Sub TestInstance_IsDead(sender As Object, e As EventArgs) Handles TestInstance.IsDead
    10. MessageBox.Show("It's dead!")
    11. Me.Close()
    12. End Sub
    13. End Class
    14. Public Class TestClass
    15. Private _Signal As Boolean = False
    16. Private CancelSignContainer As Threading.CancellationTokenSource = Nothing
    17. Public Event IsDead As EventHandler
    18. Public Property Signal As Boolean
    19. Get
    20. Return _Signal
    21. End Get
    22. Set(value As Boolean)
    23. _Signal = value
    24. PossiblyStartTimer()
    25. End Set
    26. End Property
    27. Private Async Sub PossiblyStartTimer()
    28. If _Signal Then
    29. CancelSignContainer?.Cancel()
    30. CancelSignContainer?.Dispose()
    31. CancelSignContainer = Nothing
    32. Return
    33. End If
    34. CancelSignContainer = New Threading.CancellationTokenSource
    35. Dim CancelSign = CancelSignContainer.Token
    36. Dim WaitingTask = Threading.Tasks.Task.Delay(10000, CancelSign)
    37. Try
    38. Await WaitingTask
    39. RaiseEvent IsDead(Me, Nothing)
    40. Catch TCEx As Threading.Tasks.TaskCanceledException
    41. If WaitingTask.IsCanceled Then
    42. 'it's still alive!
    43. End If
    44. Finally
    45. CancelSignContainer.Dispose()
    46. CancelSignContainer = Nothing
    47. End Try
    48. End Sub
    49. End Class

    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.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Das Problem hier fand ich interessant, deswegen wollte ich mal schnell schauen, wie ich es angegangen wäre. Das ganze schrie für mich nach INotifyPropertyChanged, um die eigentliche Änderung des Bits schön vom Überwachen trennen. Das hier ist dabei rausgekommen - vielleicht interessiert es ja jemanden.

    C#

    C#-Quellcode

    1. using System;
    2. using System.ComponentModel;
    3. using System.Threading.Tasks;
    4. public class SignalEmitter : INotifyPropertyChanged {
    5. public event PropertyChangedEventHandler PropertyChanged;
    6. private bool _signal;
    7. public bool Signal {
    8. get { return _signal; }
    9. set {
    10. if (_signal != value) {
    11. _signal = value;
    12. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Signal)));
    13. }
    14. }
    15. }
    16. }
    17. public sealed class TimedPropertyChangedObserver : IDisposable {
    18. private INotifyPropertyChanged _subject;
    19. private readonly string _propertyToObserve;
    20. private readonly TimeSpan _delay;
    21. private int _lastChangeId;
    22. public event EventHandler TimeExceeded;
    23. public TimedPropertyChangedObserver(INotifyPropertyChanged subject, string propertyToObserve, TimeSpan delay) {
    24. _subject = subject;
    25. _propertyToObserve = propertyToObserve;
    26. _delay = delay;
    27. _subject.PropertyChanged += Subject_PropertyChanged;
    28. }
    29. private async void Subject_PropertyChanged(object sender, PropertyChangedEventArgs e) {
    30. if (e.PropertyName == _propertyToObserve) {
    31. _lastChangeId++;
    32. var thisChangeId = _lastChangeId;
    33. await Task.Delay(_delay);
    34. if (_lastChangeId == thisChangeId) {
    35. TimeExceeded?.Invoke(this, EventArgs.Empty);
    36. }
    37. }
    38. }
    39. public void Dispose() {
    40. _subject.PropertyChanged -= Subject_PropertyChanged;
    41. _subject = null;
    42. }
    43. }
    44. public class Program {
    45. static void Main(string[] args) {
    46. var subject = new SignalEmitter();
    47. using var observer = new TimedPropertyChangedObserver(subject, nameof(SignalEmitter.Signal), TimeSpan.FromSeconds(5));
    48. observer.TimeExceeded += (s, e) => Console.WriteLine("The object died.");
    49. Console.WriteLine("Press ENTER to change the property.");
    50. while (true) {
    51. Console.ReadLine();
    52. subject.Signal = !subject.Signal;
    53. Console.WriteLine($"Signal is now {subject.Signal}.");
    54. }
    55. }
    56. }


    (Mit Code Converter, evtl. nicht perfektes VB):
    VB

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.ComponentModel
    3. Imports System.Threading.Tasks
    4. Public Class SignalEmitter
    5. Implements INotifyPropertyChanged
    6. Public Event PropertyChanged As PropertyChangedEventHandler
    7. Private _signal As Boolean
    8. Public Property Signal As Boolean
    9. Get
    10. Return _signal
    11. End Get
    12. Set(ByVal value As Boolean)
    13. If _signal <> value Then
    14. _signal = value
    15. PropertyChanged?.Invoke(Me, New PropertyChangedEventArgs(NameOf(Signal)))
    16. End If
    17. End Set
    18. End Property
    19. End Class
    20. Public NotInheritable Class TimedPropertyChangedObserver
    21. Implements IDisposable
    22. Private _subject As INotifyPropertyChanged
    23. Private ReadOnly _propertyToObserve As String
    24. Private ReadOnly _delay As TimeSpan
    25. Private _lastChangeId As Integer
    26. Public Event TimeExceeded As EventHandler
    27. Public Sub New(ByVal subject As INotifyPropertyChanged, ByVal propertyToObserve As String, ByVal delay As TimeSpan)
    28. _subject = subject
    29. _propertyToObserve = propertyToObserve
    30. _delay = delay
    31. AddHandler _subject.PropertyChanged, AddressOf Subject_PropertyChanged
    32. End Sub
    33. Private Async Sub Subject_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
    34. If e.PropertyName = _propertyToObserve Then
    35. _lastChangeId += 1
    36. Dim thisChangeId = _lastChangeId
    37. Await Task.Delay(_delay)
    38. If _lastChangeId = thisChangeId Then
    39. TimeExceeded?.Invoke(Me, EventArgs.Empty)
    40. End If
    41. End If
    42. End Sub
    43. Public Sub Dispose()
    44. RemoveHandler _subject.PropertyChanged, AddressOf Subject_PropertyChanged
    45. _subject = Nothing
    46. End Sub
    47. End Class
    48. Public Class Program
    49. Private Shared Sub Main(ByVal args As String())
    50. Dim subject = New SignalEmitter()
    51. Using observer = New TimedPropertyChangedObserver(subject, NameOf(SignalEmitter.Signal), TimeSpan.FromSeconds(5))
    52. observer.TimeExceeded += Function(s, e) Console.WriteLine("The object died.")
    53. Console.WriteLine("Press ENTER to change the property.")
    54. While True
    55. Console.ReadLine()
    56. subject.Signal = Not subject.Signal
    57. Console.WriteLine($"Signal is now {subject.Signal}.")
    58. End While
    59. End Sub
    60. End Class