Threads synchronisieren



  • Hallo,

    Ich schreibe derzeit ein Plugin für ein Programm. Da dieses Programm aber keine Plugins vorgesehen hat und deshalb darauf verzichtet hat irgendeine Schnittstelle anzubieten, verwende ich die DLL - Injektion.
    Nun ist es für mich außerordentlich wichtig, dass der Zugriff auf einen bestimmten Speicherbereich zwischen den Threads des Programms und meiner DLL synchronisiert wird. Ist das aus meiner DLL möglich? Wenn ja, wie?

    Mfg



  • Ohne source vergiss es besser



  • Wie wärs mit einer CriticalSection!?



  • Das Problem ist, ich weiß nicht, wie genau die CriticalSections intern funktionieren. Ich habe ja keinen Zugriff auf die Threads des Programms. Würde es genügen, wenn ich eine CriticalSection in meiner DLL initialisiere und auf meinen Thread anwende? Sprich halten sich die anderen Threads aus dem Prozess, die ich nicht verändern kann, auch an die Semaphorensperre?



  • Du hast offenbar ein ziemlich grundlegendes Missverständnis was Synchronisation angeht. Man wendet eine CriticalSection nicht "auf einen Thread an". Das macht keinen Sinn. Du solltest dir wohl erstmal die Grundlagen von Multithreading und Synchronisation anschaun...



  • dot schrieb:

    Wie wärs mit einer CriticalSection!?

    Dazu benötigt man in allen an der Synchronisation zu beteiligenden Threads Zugriff auf ein gemeinsames (globales) CriticalSection - Objekt. Wie soll das gehen, wenn man auf die bereits vorhandenen Programmteile keine Einflussmöglichkeit hat?



  • Gegenfrage: Wo genau siehst du das Problem!?



  • Och ich habe das mit dem Multithreading schon ganz gut verstanden, nur war das in Java wesentlich einfacher 😉 Ich weiß nicht, ob Boost vielleicht etwas vergleichbares, wie Java mit dem Schlüsselwort "synchronized" anbietet, aber mein Problem bleibt doch weiterhin bestehen.
    Ich habe derzeit keinen Dunst, wie viele Threads aus dem Programm den wichtigen Speicherbereich gemeinsam verwenden. Ich weiß auch nicht, ob diese Threads synchronisiert wurden. Ich weiß nur, dass ich um jeden Preis verhindern muss, dass ein anderer Thread mit dem Speicher arbeitet, wenn ich ihn in meiner DLL brauche.
    Ich hatte mir schon überlegt einfach mal das ganze Programm "schlafen zu legen", also mit SuspendThread() einfach mal alle Threads zum Pausieren zu bewegen, aber das hielt ich für eine sehr suboptimale Idee. Zwar verwende ich den besagten Speicher nur ein, höchstens zweimal, aber ich hoffte trotzdem, dass es da elegantere Methoden gibt, als die Haudrauf-Variante.



  • Um was für einen Speicherbereich handelt es sich da genau? Legst du den an? Wie erfolgt der Zugriff darauf?



  • Nein der Speicher wird vom Programm angelegt. Es sind ca. 5Bytes im Arbeitsspeicher, die ich über normale Pointer anspreche, bei denen ich sicher gehen muss, dass kein anderer Thread auf diese Zugriff hat. Es sind genauer 5Bytes ausführbarer Code einer Funktion, die ich verändern möchte. Deshalb will ich verhindern, dass genau dann die Funktion ausgeführt wird, wenn ich gerade dabei bin ein bisschen was umzuschreiben.





  • Aber nurmal ne rein prinzipielle Frage: Ich vermute mal du willst einen jmp reinschreiben um eine Funktion in deinen eigenen Code umzuleiten!? Warum genau musst du hier synchronisieren?



  • dot schrieb:

    Gegenfrage: Wo genau siehst du das Problem!?

    Ich erstelle in meinem Code ein Critical Section - Objekt, um sicherzustellen, dass meine synchronisationsbedürftigen Aktionen nicht gleichzeitig ausgeführt werden können.
    Wie bewege ich den fremden Code dazu, auch dieses mein Critical Section - Objekt zu benutzen, bevor er das tut, was ich synchronisieren will?
    Ich denke, ich weiß ja nicht einmal an welcher Codestelle das passiert?



  • Belli schrieb:

    Wie bewege ich den fremden Code dazu, auch dieses mein Critical Section - Objekt zu benutzen, bevor er das tut, was ich synchronisieren will?
    Ich denke, ich weiß ja nicht einmal an welcher Codestelle das passiert?

    Ich ging natürlich davon aus dass die Notwendigkeit zur Synchronisation Objekte die deinem hinzugefügten Code gehören betrifft. Natürlich kannst du die Critical Section nicht einfach so in den Code einer fremden Binary reinhämmern (nicht dass das prinzipiell unmöglich wär, aber es is weder einfach noch schön).



  • Aber nurmal ne rein prinzipielle Frage: Ich vermute mal du willst einen jmp reinschreiben um eine Funktion in deinen eigenen Code umzuleiten!? Warum genau musst du hier synchronisieren?

    Nicht ganz, aber sowas Ähnliches. Ich stell mir das etwas schlecht vor, wenn der Abschnitt genau dann ausgeführt wird, wenn ich daran rumpfusche, oder etwa nicht?



  • dot schrieb:

    Ich ging natürlich davon aus dass die Notwendigkeit zur Synchronisation Objekte die deinem hinzugefügten Code gehören betrifft.

    Okay ... ich interpretiere das hier anders.

    iBlock schrieb:

    Nun ist es für mich außerordentlich wichtig, dass der Zugriff auf einen bestimmten Speicherbereich zwischen den Threads des Programms und meiner DLL synchronisiert wird.



  • Wenn alle Funktionen, die auf die DLL zugreifen auch in DLLs sind, kannst eventuell neue Funktionen schreiben die erst die Critical Section und dann den eigentlichen code der Dll aufrufen. Dann mußt du "nur" noch die Aufrufadressen von den fremden DLLs auf deine neue Funktionen umbiegen.

    Das Umbiegen der Aufrufadressen geht so:
    http://www.mpcforum.com/showthread.php?55898-SwapBuffers-usage
    (Den Code mittels DLL injection in die Frede Dll laden und dann ReDirectFunction aufrufen)

    Aber ob das wirklich funktioniert ...?



  • iBlock schrieb:

    Nun ist es für mich außerordentlich wichtig, dass der Zugriff auf einen bestimmten Speicherbereich zwischen den Threads des Programms und meiner DLL synchronisiert wird. Ist das aus meiner DLL möglich?

    Nein, das ist nicht möglich.
    Nicht ohne das Programm anzupassen. Was du ja nicht kannst.



  • wie schon oben geschrieben:
    Ohne den anderen Programmteil zu verändern hast du da wirkliche keine Chance. Selbst den anderen Thread schlafen zu legen greift nicht durch, du weisst ja nicht, wann der dort liest und/oder schreibt und was genau der mit den Daten macht.

    Wenn du da trotzdem "rumfummelst", produzierst du im besten Fall eine Zeitbombe - es funktioniert, aber irgendwann schmiert das Programm dann gnadenlos ab.

    Ulli



  • iBlock schrieb:

    Hallo,
    Nun ist es für mich außerordentlich wichtig, dass der Zugriff auf einen bestimmten Speicherbereich zwischen den Threads des Programms und meiner DLL synchronisiert wird. Ist das aus meiner DLL möglich? Wenn ja, wie?

    Also schön wird das nicht werden. Aber ich sehe immerhin folgende Optionen:

    • Du veränderst den fraglichen Code, bevor du die anderen Threads startest.
    • Du fügst eine atomar schreibbare Abzweigung (also einen 1 Wort langen Sprung-Befehl) ein auf einen Warteschleifen-Code (der dann zweckdienlich Synchronisation zum Warten nutzt), in dem du eventuell herangeraste Threads einsammelst, während die Veränderungen vor sich gehen. Auf der 8086-Architektur bieten sich der Befehl für Software-Interrupts INT # an.
    • Du nutzt Hardware-breakpoints, um andere Threads von der kritischen Stelle abzuleiten. Ansonsten Warteschleifen-Code ähnlich der Variante oben mit INT #.

    Vorsicht ist aber auch geboten gegen Threads, die von irgendwo her mitten in die fragliche Bytesequenz hineinspringen, also nicht nur an den Anfang des Abschnitts. Wenn du das nicht ausschließen kannst, wird es überhaupt kompliziert. Dann musst du unter anderem acht geben, dass die Befehle des Codes, den du einfügst jeweils dieselben Startadressen haben (oder mehr) wie die ursprüngliche Befehlssequenz (wie immer man die Wörter auch lesen mag). Im ungünstigen Fall sind nur Befehle der Wortlänge 1 erlaubt. Hier könntest du an NOP denken, doch mit nur NOPs kommt man eben auch nicht weit. Wieder könnte INT # dein Freund sein.


Anmelden zum Antworten