Deadlock mit Schleife und BackgroundWorker

  • VB.NET
  • .NET (FX) 1.0–2.0

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Vultrax.

    Deadlock mit Schleife und BackgroundWorker

    Ich lese Bytes aus meinem Speicher aus und vergleiche diese mit der als Parameter angebenden Zahl.
    Das Problem ist, dass ich durch die Schleife einen Deadlock bekomme und IsBusy weiterhin auf True steht, obwohl der BackgroundWorker bereits seine Arbeit vollendet hat.

    Wenn ich System.Windows.Forms.Application.DoEvents() einfüge, wird der Vorgang ausgeführt, allerdings sind manchmal bis zu +30.000 Einträge einfach nur Null, was aber nicht sein kann, da Address niemals Null ist.

    VB.NET-Quellcode

    1. For Each Address As Integer In ReadMemory.TEST(1)
    2. MessageBox.Show(Hex(Address))
    3. Next

    VB.NET-Quellcode

    1. Private BackgroundWorker1_Bytes() As Byte
    2. Private BackgroundWorker2_Bytes() As Byte
    3. Private BackgroundWorker1_Address As Integer
    4. Private BackgroundWorker2_Address As Integer
    5. Private NumberToFind As Integer
    6. Private Addresses As New List(Of Integer)
    7. Public Function TEST(ByVal MyNumber As Byte) As Integer()
    8. NumberToFind = MyNumber
    9. For Address As Integer = &H4096 To &H64000 Step &H0
    10. System.Windows.Forms.Application.DoEvents() 'Löst das Deadlock-Problem, sorgt aber für jede Menge unerklärliche Null-Adressen in meinem Array (nicht in diesem Beispiel)
    11. If BackgroundWorker1.IsBusy = False OrElse BackgroundWorker2.IsBusy = False Then
    12. If BackgroundWorker1.IsBusy = False Then
    13. BackgroundWorker1_Address = Address
    14. BackgroundWorker1_Bytes = {5, 2, 3, 1, 1, 7, 9, 4, 8, 1, 3}
    15. BackgroundWorker1.RunWorkerAsync()
    16. ElseIf BackgroundWorker2.IsBusy = False Then
    17. BackgroundWorker2_Address = Address
    18. BackgroundWorker2_Bytes = {7, 1, 3, 9, 1, 8, 3, 2, 8, 2, 4}
    19. BackgroundWorker2.RunWorkerAsync()
    20. End If
    21. Address = Address + &H4096
    22. End If
    23. Next
    24. Addresses.Sort()
    25. Return Addresses.ToArray
    26. End Function
    27. Private WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker
    28. Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    29. For Index As Integer = 0 To BackgroundWorker1_Bytes.Length - 1
    30. If BackgroundWorker1_Bytes(Index) = NumberToFind Then
    31. Addresses.Add(BackgroundWorker1_Address + Index)
    32. End If
    33. Next
    34. End Sub
    35. Private WithEvents BackgroundWorker2 As New System.ComponentModel.BackgroundWorker
    36. Private Sub BackgroundWorker2_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
    37. For Index As Integer = 0 To BackgroundWorker2_Bytes.Length - 1
    38. If BackgroundWorker2_Bytes(Index) = NumberToFind Then
    39. Addresses.Add(BackgroundWorker2_Address + Index)
    40. End If
    41. Next
    42. End Sub


    Wenn ich es ohne die BackgroundWorker mache, dauert der Vorgang meist mehr als eine Minute, was aber viel zu lange ist.

    Könnt Ihr mir weiterhelfen? :)
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford

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

    Ist dir bewusst das die Schleife For Address As Integer = &H4096 To &H64000 Step &H0 nie zum Ende kommt? Lass dir mal Adress in der Schleife ausgeben.

    VB.NET-Quellcode

    1. For Address As Integer = &H4096 To &H64000 Step &H0
    2. Debug.WriteLine(Address)
    3. Next


    Das liegt daran das du Step 0 als "Schritt" angibst, sollte schon > 0 sein.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    @Nolde - Danke erstmal für Deine Antwort.

    Das soll auch so sein, da die Adresse nur erhöht wird, wenn ein BackgroundWorker frei ist (wird durch Deadlock verhindert) und den nächsten Speicherbereich mit der Adresse übernimmt (siehe Kommentare im Code).

    VB.NET-Quellcode

    1. For Address As Integer = &H4096 To &H64000 Step &H0
    2. If BackgroundWorker1.IsBusy = False OrElse BackgroundWorker2.IsBusy = False Then 'IsBusy ändert sich nicht mehr zu False (auch wenn der BackgroundWorker fertig ist)
    3. If BackgroundWorker1.IsBusy = False Then
    4. BackgroundWorker1_Address = Address
    5. BackgroundWorker1_Bytes = {5, 2, 3, 1, 1, 7, 9, 4, 8, 1, 3}
    6. BackgroundWorker1.RunWorkerAsync()
    7. ElseIf BackgroundWorker2.IsBusy = False Then
    8. BackgroundWorker2_Address = Address
    9. BackgroundWorker2_Bytes = {7, 1, 3, 9, 1, 8, 3, 2, 8, 2, 4}
    10. BackgroundWorker2.RunWorkerAsync()
    11. End If
    12. Address = Address + &H4096 'Addiere (in Hexadezimal) 4096 (16534) zu "Address"
    13. End If
    14. Next
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Vultrax“ ()

    1. Post#1, Zeile#71-75: sollte da nicht was mit BackGroundWorker2 stehen?
    2. Warum eine For-Schleife mit Step 0 verwenden, wenn Du die Adressen nur manuell erhöhst? Dafür könnte doch eine Do-While-Schleife- genutzt werden.
    3. Backgroundworker? Da gibt es doch Async/Await heutzutage.
    4. Viele überflüssige Leerzeilen in Deinem geposteten Code.
    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.
    1). Hoppla, da sind mir wohl ein paar Fehler beim nachschreiben passiert (Problem besteht trotzdem).

    2). Ja, da es aber die selbe Wirkung hat und meiner Meinung nach etwas übersichtlicher aussieht (ich muss keine extra Variable deklarieren), mache ich es gelegentlich so.

    3). Könntest Du mir etwas passendes dazu schicken?

    4). Ich mache immer viele Leerzeichen um die Übersicht zu behalten, habe so meine Probleme bei Code der nur zusammengeschrieben ist.
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford

    Vultrax schrieb:

    Ich lese Bytes aus meinem Speicher aus und vergleiche diese mit der als Parameter angebenden Zahl.

    Das machst Du mit gezeigtem Code nicht. Oder vielleicht versteh ich Deinen Code auch nicht. Aber Du übergibst mit ReadMemory.TEST(1) z.B. die 1. Im Code vergleichst Du diese 1 mit den festcodierten Zahlen aus Zeile#25 und #33 auch Post#1. Ich weiß nicht, ob das zum Ziel führt, aber ein Bytes-aus-dem-Speicher-auslesen ist das meines Erachtens nicht.

    VB.NET-Quellcode

    1. For Index As Integer = 0 To BackgroundWorker1_Bytes.Length - 1 'gehe alle folgenden Zahlen durch: 5, 2, 3, 1, 1, 7, 9, 4, 8, 1, 3
    2. If BackgroundWorker1_Bytes(Index) = NumberToFind Then 'wenn 5 = 1, … wenn 2 = 1, … wenn 3 = 1, … wenn 1 = 1 (Treffer)
    3. Addresses.Add(BackgroundWorker1_Address + Index) 'dann Adresse (z.B. &H4096) + 3 in die Adressliste
    4. End If
    5. Next

    Nächster Punkt ist, dass Adressbereiche tw. ungeprüft übersprungen werden, da Du die Adresserhöhung durchführst, wenn einer der beiden BGWs untätig ist und eine neue Aufgabe bekommt. Das heißt, dass der 2. BGW den Adressbereich nicht zu Gesicht gekommt.
    Beispiel:
    Du beginnst bei &H4096. Deine Bedingung sagt: Wenn einer der beiden BGWs inaktiv ist, soll er (also als erstes BGW1) aktiv werden (was immer das auch heißen mag, bei diesem BGW-Code) und dann wird der Adressbereich erhöht. Das heißt: BGW2 bekommt die Adresse &H4096 nicht zu sehen. Oder soll das so sein, sodass die beiden sich immer abwechseln? Ergäbe für mich zwar noch weniger Sinn, aber in kenn ja Deine Intention dahinter nicht.

    @all: Ich arbeite selten mit mehreren Async-Tasks gleichzeitig. Verbesserungen: Immer her damit.
    Mein Vorschlag

    VB.NET-Quellcode

    1. Private TaskList As New List(Of Threading.Tasks.Task)
    2. Private Addresses As New List(Of Integer)
    3. Public Function TEST(ByVal NumberToFind As Byte) As Integer()
    4. TaskList.Add(LookFor(NumberToFind, {5, 2, 3, 1, 1, 7, 9, 4, 8, 1, 3}))
    5. TaskList.Add(LookFor(NumberToFind, {7, 1, 3, 9, 1, 8, 3, 2, 8, 2, 4}))
    6. Threading.Tasks.Task.WaitAll(TaskList.ToArray)
    7. Addresses.Sort()
    8. Return Addresses.ToArray
    9. End Function
    10. Private Async Function LookFor(DigitToFind As Byte, ArrayToUse As Byte()) As Threading.Tasks.Task
    11. Await Threading.Tasks.Task.Run(Sub()
    12. For Address = &H4096 To &H64000 Step &H4096
    13. For Index As Integer = 0 To ArrayToUse.Length - 1
    14. If ArrayToUse(Index) = DigitToFind Then
    15. Addresses.Add(Address + Index)
    16. End If
    17. Next
    18. Next
    19. End Sub)
    20. End Function
    21. Private Sub BtnEnd_Click(sender As Object, e As EventArgs) Handles BtnEnd.Click
    22. Close()
    23. End Sub
    24. Private Async Sub cmdFileDlg_Click(sender As Object, e As EventArgs) Handles cmdFileDlg.Click
    25. Dim MatchingAddresses As Integer() = Nothing
    26. Await Threading.Tasks.Task.Run(Sub()
    27. MatchingAddresses = TEST(1)
    28. End Sub)
    29. For Each Address As Integer In MatchingAddresses
    30. MessageBox.Show(Hex(Address))
    31. Next
    32. End Sub


    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 2 mal editiert, zuletzt von „VaporiZed“ ()

    VaporiZed schrieb:

    Das machst Du mit gezeigtem Code nicht. Oder vielleicht versteh ich Deinen Code auch nicht. Aber Du übergibst mit ReadMemory.TEST(1) z.B. die 1. Im Code vergleichst Du diese 1 mit den festcodierten Zahlen aus Zeile#25 und #33 auch Post#1. Ich weiß nicht, ob das zum Ziel führt, aber ein Bytes-aus-dem-Speicher-auslesen ist das meines Erachtens nicht.

    Der Code ist keine 1:1-Kopie und abgespeckt worden. Die Bytes und die Adressen erhalte ich durch VirtualQueryEx und ReadProcessMemory (im original Code). Das einzige Problem ist der Deadlock, das Auslesen und Vergleichen funktioniert wunderbar, wenn man es ohne BackgroundWorker macht (im UI-Thread), oder das unsaubere (mir ist bekannt, dass man es nicht nutzen soll) Application.DoEvents() reinhaut und dafür die ganzen unerklärlichen Nullen im Array in kauf nimmt (und evtl. auch weitere Bugs).

    VaporiZed schrieb:

    Nächster Punkt ist, dass Adressbereiche tw. ungeprüft übersprungen werden, da Du die Adresserhöhung durchführst, wenn einer der beiden BGWs untätig ist und eine neue Aufgabe bekommt. Das heißt, dass der 2. BGW den Adressbereich nicht zu Gesicht gekommt.
    Beispiel:
    Du beginnst bei &H4096. Deine Bedingung sagt: Wenn einer der beiden BGWs inaktiv ist, soll er (also als erstes BGW1) aktiv werden (was immer das auch heißen mag, bei diesem BGW-Code) und dann wird der Adressbereich erhöht. Das heißt: BGW2 bekommt die Adresse &H4096 nicht zu sehen. Oder soll das so sein, sodass die beiden sich immer abwechseln? Ergäbe für mich zwar noch weniger Sinn, aber in kenn ja Deine Intention dahinter nicht.

    Genau so soll es sein, da solange ein BackgroundWorker beschäftigt ist, der 2, 3, 4 oder 5 bereits den nächsten ausgelesenen Byte-Array überprüft und dadurch der Vorgang enorm beschleunigt wird (wenn man dynamisch viele Threads festlegen könnte, wäre das natürlich optimal).

    VaporiZed schrieb:

    @all: Ich arbeite selten mit mehreren Async-Tasks gleichzeitig. Verbesserungen: Immer her damit.
    Mein Vorschlag

    VB.NET-Quellcode

    1. Private TaskList As New List(Of Threading.Tasks.Task)
    2. Private Addresses As New List(Of Integer)
    3. Public Function TEST(ByVal NumberToFind As Byte) As Integer()
    4. TaskList.Add(LookFor(NumberToFind, {5, 2, 3, 1, 1, 7, 9, 4, 8, 1, 3}))
    5. TaskList.Add(LookFor(NumberToFind, {7, 1, 3, 9, 1, 8, 3, 2, 8, 2, 4}))
    6. Threading.Tasks.Task.WaitAll(TaskList.ToArray)
    7. Addresses.Sort()
    8. Return Addresses.ToArray
    9. End Function
    10. Private Async Function LookFor(DigitToFind As Byte, ArrayToUse As Byte()) As Threading.Tasks.Task
    11. Await Threading.Tasks.Task.Run(Sub()
    12. For Address = &H4096 To &H64000 Step &H4096
    13. For Index As Integer = 0 To ArrayToUse.Length - 1
    14. If ArrayToUse(Index) = DigitToFind Then
    15. Addresses.Add(Address + Index)
    16. End If
    17. Next
    18. Next
    19. End Sub)
    20. End Function
    21. Private Sub BtnEnd_Click(sender As Object, e As EventArgs) Handles BtnEnd.Click
    22. Close()
    23. End Sub
    24. Private Async Sub cmdFileDlg_Click(sender As Object, e As EventArgs) Handles cmdFileDlg.Click
    25. Dim MatchingAddresses As Integer() = Nothing
    26. Await Threading.Tasks.Task.Run(Sub()
    27. MatchingAddresses = TEST(1)
    28. End Sub)
    29. For Each Address As Integer In MatchingAddresses
    30. MessageBox.Show(Hex(Address))
    31. Next
    32. End Sub



    Deinen Code werde ich mir anschauen sobald ich Zeit habe! :)
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Vultrax“ ()

    Ich habe den Code jetzt mal durchgeschaut und festgestellt, dass ich wohl etwas vergessen habe zu erwähnen.
    Die For-Schleife kann nicht innerhalb des Threads sein, da ich die Bytes bei jeder Region erneut auslese und weiter zu nächsten gültigen Adresse mit VirtualQueryEx springe (zwischen MinAddress [&H4096] und MaxAddress [&H64000] gibt es auch Bereiche die nicht von der Anwendung belegt sind).

    CodeProject: codeproject.com/Articles/71622…-to-Scan-a-Process-Memory (siehe "How To")

    Ich versuche dies mit Multithreading (mit mehr als nur einem Thread) umzusetzen.
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford