Fragen kurz
Ich verwende C ++ und Java in einem Prozess über JNI. Für den fraglichen Anwendungsfall greifen sowohl ein C ++ - Thread als auch ein Java-Thread auf dieselben Daten zu, sie tun dies auf der C ++ - Seite, und ich möchte den Zugriff ordnungsgemäß synchronisieren.
Bisher war fast meine gesamte JNI-Thread-Synchronisierung auf der Java-Seite, wo die Antwort offensichtlich ist: Verwenden Sie das bereitgestellte Java-Concurrency-Paket und die integrierten Sprachen für den gemeinsamen Zugriff. Leider ist die Antwort auf der C ++ Seite nicht so offensichtlich.
Was ich bisher versucht habe Kurz
Ich habe versucht, einen pthreads-Mutex zu verwenden, der denkt, dass es funktionieren könnte, obwohl ich keine pthreads verwende, um Threads zu erstellen, die aber gelegentlich beim Sperren hängen bleiben - ich werde ein Beispiel dafür weiter unten zeigen.
>In meiner derzeitigen, spezifischen Verwendung fragt c ++ nach Änderungen, die von Java mit einem 1-Sekunden-Timer geliefert werden (was ich nicht gerne hätte, aber ich bin mir nicht sicher, wie ich es ereignisgesteuert machen würde Legacy-C ++ - Code). Der Java-Thread stellt Daten bereit, indem eine native Funktion aufgerufen wird, und c ++ kopiert die Daten in eine C ++ - Struktur.
Dies ist die Art der Situation im Code (passiert bei 2 Threads, Thread1 und Thread2):
Codebeispiel
Bemerken Sie eine SSCCE, da es Definitionen für TheData
und TheDataWrapper
fehlt, aber es spielt keine Rolle, was sie enthalten. Angenommen, sie enthalten nur ein paar öffentliche int
s, wenn das Ihrem Denkprozess hilft (obwohl es in meinem Fall mehrere Arrays von int und Arrays von float gibt).
C ++:
%Vor%Java:
%Vor% Wenn ich versucht habe, pthread wie unten beschrieben zu sperren, bleibt die Ausführung manchmal in pthread_mutex_lock
hängen. Es sollte in dieser Situation kein Deadlock geben, aber um weiter zu testen, habe ich ein Szenario ausgeführt, in dem supplyData
überhaupt nicht aufgerufen wurde (es wurden keine Daten geliefert), also sollte kein Deadlock möglich gewesen sein, doch der erste Aufruf an poll
wird gelegentlich trotzdem hängen. Vielleicht ist die Verwendung eines Pthreads-Mutex in dieser Situation keine gute Idee? Oder vielleicht habe ich etwas Dummes gemacht und es immer wieder übersehen.
Bisher habe ich versucht, Pthreads wie folgt zu verwenden:
Codebeispiel
C ++:
%Vor%Eine andere Option, über die ich nachgedacht, aber noch nicht getan habe
Ich habe auch erwogen, JNI zu verwenden, um in Java zurückzurufen, um eine Sperre unter Verwendung des Java-Nebenläufigkeitssteuerelements anzufordern. Das sollte funktionieren, da jeder Thread bei Bedarf auf der Java-Seite blockieren sollte. Da der Zugriff auf Java von C ++ jedoch sehr ausführlich ist, hatte ich gehofft, diese Kopfschmerzen vermeiden zu können. Ich könnte wahrscheinlich eine C ++ - Klasse machen, die JNI-Aufrufe in Java kapselt, um eine Java-Sperre anzufordern; das würde den C ++ - Code vereinfachen, obwohl ich mich über den Overhead des Hin- und Hertransfers über JNI nur für Thread-Locks wundere.
Es scheint, dass dies nicht notwendig ist, nach dem Kommentar von @Radiodef. Es scheint, dass JNI MonitorEnter
/ MonitorExit
-Funktionen enthält, die bereits das Sperren auf der C ++ - Seite behandeln. Es gibt Fallstricke, wenn Sie diese gleichzeitig mit herkömmlichen Sperren auf der Java-Seite verwenden, also lesen Sie bitte hier vor der Verwendung. Ich werde das ausprobieren, und ich erwarte, dass MonitorEnter
/ MonitorExit
die Antwort sein wird und ich empfehle @Radiodef, eine Antwort aus dem Kommentar zu machen.
Wie kann ich das richtig synchronisieren? Sollte pthread_mutex_ (un) lock arbeiten? Wenn nicht, was kann ich zum Synchronisieren zwischen dem C ++ - Thread und dem Java-Thread verwenden?
Hier wird kein JNI-spezifischer C ++ - Code bereitgestellt, da die JNI-Bridge funktioniert und ich Daten hin und her übertragen kann. Die Frage bezieht sich speziell auf die korrekte Synchronisation zwischen C ++ / Java-Threads, die ansonsten korrekt kommunizieren.
Wie bereits erwähnt, würde ich das Wahlverfahren lieber vermeiden, aber das könnte eine andere Frage sein. Der Legacy-C ++ - Code zeigt seinen Teil der Benutzeroberfläche in X / Motiv an, und wenn ich mich richtig erinnere, ist der C ++ - Thread oben der Ereignis-Thread für die Anzeige. Der Java-Thread wird der Java-Event-Dispatch-Thread sein, sobald die Java-Benutzerschnittstelle für diese Klasse eingesteckt ist, obwohl der Java-Thread vorerst ein automatisierter Test-Thread ist; So oder so, es ist ein separater Java-Thread.
Der C ++ - Thread ist an die JVM angehängt. Tatsächlich ist dies der C ++ - Thread, der die JVM erstellt hat, daher sollte sie standardmäßig angehängt sein.
Es ist mir gelungen, andere Java-Benutzeroberflächenelemente in dieses Programm zu integrieren, aber dies ist das erste Mal, dass C ++ nicht-atomare Daten von Java benötigt, die synchronisiert werden müssen. Gibt es einen allgemein akzeptierten richtigen Weg, dies zu tun?
Wenn beide Threads an die JVM angehängt sind, können Sie über die Funktionen JNIEnv
und MonitorEnter(jobject)
auf die Synchronisation des JNI zugreifen. So wie es klingt, erwirbt MonitorExit(jobject)
eine Sperre für das bereitgestellte MonitorEnter
, und jobject
gibt die Sperre für das bereitgestellte MonitorExit
frei.
HINWEIS: Es gibt einige Fallstricke, auf die Sie achten sollten! Beachten Sie den vorletzten Absatz von jobject
's Beschreibung und den letzten Absatz von MonitorEnter
' s Beschreibung über das Mischen und Vergleichen von MonitorExit
/ MonitorEnter
mit anderen ähnlichen Mechanismen, die Sie sonst für kompatibel halten könnten.
Siehe hier
MonitorEnter
jint MonitorEnter (JNIEnv * env, Projektobjekt);
Gibt den Monitor an, der dem zugrunde liegenden Java-Objekt zugeordnet ist nach obj. Gibt den Monitor ein, der dem Objekt zugeordnet ist, auf das verwiesen wird von obj. Die Obj-Referenz darf nicht NULL sein. Jedes Java-Objekt hat a Monitor damit verbunden. Wenn der aktuelle Thread bereits Eigentümer des Monitor verbunden mit obj, erhöht es einen Zähler im Monitor Gibt an, wie oft dieser Thread in den Monitor gelangt ist. Ob Der mit obj verknüpfte Monitor gehört keinem Thread, der Der aktuelle Thread wird zum Besitzer des Monitors und legt den Eintrag fest Zähle diesen Monitor auf 1. Wenn ein anderer Thread bereits den Monitor besitzt verknüpft mit obj wartet der aktuelle Thread bis der Monitor ist veröffentlicht, versucht dann erneut, das Eigentum zu erwerben.
Ein über einen MonitorEnter JNI-Funktionsaufruf eingegebener Monitor kann nicht verwendet werden mit der Java Virtual Machine-Anweisung monitorexit beendet oder a synchronisierte Methodenrückgabe Ein MonitorEnter JNI-Funktionsaufruf und a monitorenter Java virtual machine Anweisung kann Rennen in die Monitor mit dem gleichen Objekt verbunden.
Um Deadlocks zu vermeiden, wurde ein Monitor über einen MonitorEnter JNI eingegeben Der Funktionsaufruf muss mit dem MonitorExit JNI-Aufruf beendet werden, sofern nicht Mit dem Aufruf DetachCurrentThread wird JNI implizit freigegeben Monitore.
VERBINDUNG :
Index 217 in der JNIEnv-Schnittstellenfunktionstabelle.
PARAMETER :
env: der JNI-Schnittstellenzeiger.
obj: ein normales Java-Objekt oder Klassenobjekt.
RETURNS :
Gibt beim Erfolg "0" zurück; gibt bei einem Fehler einen negativen Wert zurück.
und
MonitorExit
jint MonitorExit (JNIEnv * env, Projektobjekt);
Der aktuelle Thread muss der Besitzer des zugeordneten Monitors sein das zugrunde liegende Java-Objekt, auf das sich obj bezieht. Der Thread wird verringert der Zähler zeigt an, wie oft er eingegeben wurde Monitor. Wenn der Wert des Zählers Null wird, wird der aktuelle Thread angezeigt gibt den Monitor frei.
Systemeigener Code darf MonitorExit nicht zum Beenden eines Monitors verwenden, durch den er eingegeben wurde eine synchronisierte Methode oder eine monitorenter Java Virtual Machine Anweisung.
VERKNÜPFUNG :
Index 218 in der JNIEnv-Schnittstellenfunktionstabelle.
PARAMETER :
env: der JNI-Schnittstellenzeiger.
obj: ein normales Java-Objekt oder Klassenobjekt.
RETURNS :
Gibt beim Erfolg "0" zurück; gibt bei einem Fehler einen negativen Wert zurück.
AUSNAHMEN :
IllegalMonitorStateException: Wenn der aktuelle Thread nicht die überwachen.
Also sollte der C ++ - Code in der Frage, die versucht, pthreads zu verwenden, wie folgt geändert werden (der Code geht davon aus, dass der MonitorExit
-Pointer irgendwie zuvor in typischer JNI-Art erfasst wurde):
Ein großes Lob an @Radiodef, der die Antwort gegeben hat. Leider war es als Kommentar. Ich wartete bis zum nächsten Tag, um Radiodef eine Antwort zu geben, also mache ich es jetzt. Danke, Radiodef, dass du mir den Anstupser gegeben hast, um das zu beheben.
Tags und Links java c++ multithreading synchronization jni