1/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vláknové programování část XII Lukáš Hejmánek, Petr Holub {xhejtman,hopet}@ics.muni.cz Laboratoř pokročilých síťových technologií PV192 2011–05–12 2/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Přehled přednášky Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní 3/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a GUI GUI jsou obecně řízená událostmi ◾ asynchronní vznik události ◾ obvykle se jedno vlákno stará o obsluhu událostí – “event loop” Problémy událostmi řízeného modelu GUI ◾ problém předávání změn z jiných vláken ◾ problém s dlouho běžícími úlohami obsluhujícími událost 4/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a GUI Možnosti synchronizace mezi vlákny a GUI 1. thread-safe/multi-thread GUI nepoužívá se Graham Hamilton: Multithreaded toolkits: A failed dream? http://weblogs.java.net/blog/kgh/archive/2004/10/multithreaded_t.html 2. explicitní zamykání např. Gtk s použitím Gdk zámků 3. předávání práce GUI vláknu Java SWING, QT, GtkAda Contributions 5/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Explicitní zamykání s GUI 6/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Explicitní zamykání s GUI Strategie 1. před startem GUI inicializuji zamykání 2. před startem smyčky obsluhy událostí získám zámek 3. smyčka obsluhy událostí zámek periodicky pouští 4. jiné vlákno, pokud chce kreslit, musí získat zámek a po dokončení jej pustit Problémy ◾ ověření, že při všech aktualizacích GUI získávám zámek ◾ ověření, že po všech aktualizacích GUI pouštím zámek ◾ ověření, že u callbacků nezískávám a nepouštím zámky 7/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Ada binding pro Gtk+, Glib a Gdk ◾ prakticky kompletní wrapper z pohledu Gtk+ ◾ může spolupracovat s tasky ◾ 2.14 stabilní, 2.18 v CVS Dostupné pro Windows, Linux, MacOS X http://libre.adacore.com/libre/tools/gtkada/ 8/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Inicializace Vytvoření smyčky událostí ◾ držení zámku v době startu 1 Gtk.Main.Set_Locale; Gdk.Threads.G_Init; 3 Gdk.Threads.Init; Gtk.Main.Init; 5 Init_GUI; Gdk.Threads.Enter; 7 Gtk.Main.Main; Gdk.Threads.Leave; 9 return; 9/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Modifikace z jiného vlákna Zámek pro modifikace task body Counter is 2 begin Main_Loop : 4 loop Counter_Monitor.Wait_For_Start; 6 -- because the main thread is waiting for us on termination -- we can touch Gtk objects until we signal termination; beware of ogr 8 -- more appropriate is exiting early exit Main_Loop when Counter_Monitor.Check_If_Quit; 10 Gdk.Threads.Enter; -- Ada95 syntax 12 Gtk.Button.Set_Label (Global_Window.all.Run_Button, -" Stop "); Gdk.Threads.Leave; 14 Counter_Loop : for I in 0 .. 1000 loop 16 exit Main_Loop when Counter_Monitor.Check_If_Quit; if Counter_Monitor.Check_If_Stop then 18 exit Counter_Loop; end if; 20 Gdk.Threads.Enter; Gtk.Label.Set_Label (Global_Window.all.Counter_Label, -(Integer’Imag 22 Gdk.Threads.Leave; delay 1.0; 24 end loop Counter_Loop; 10/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Modifikace z jiného vlákna Zámek pro modifikace Gdk.Threads.Enter; 2 -- Ada2005 extended syntax Global_Window.all.Run_Button.all.Set_Label (-" Run "); 4 Counter_Monitor.Finished; Global_Window.all.Run_Button.all.Set_Sensitive (True); 6 Gdk.Threads.Leave; end loop Main_Loop; 8 Counter_Monitor.Finished; end Counter; 11/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Callbacky procedure Quit is 2 begin Counter_Monitor.Quit; 4 -- BEWARE OF OGRES! May deadlock if lock is not given up! Gdk.Threads.Leave; 6 Counter_Monitor.Wait_Until_Finished; Gdk.Threads.Enter; 8 Destroy (Global_Window); Gtk.Main.Main_Quit; 10 end Quit; 12 procedure On_Quit_Button_Clicked (Button : access Gtk.Button.Gtk_Button_Record’Class) 14 is begin 16 pragma Unreferenced (Button); Quit; 18 end On_Quit_Button_Clicked; 12/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Callbacky 1 procedure On_Run_Button_Clicked (Button : access Gtk.Button.Gtk_Button_Record’Class) 3 is begin 5 if Counter_Monitor.Check_If_Running then Button.all.Set_Sensitive (False); 7 Counter_Monitor.Stop; else 9 Counter_Monitor.Start; end if; 11 end On_Run_Button_Clicked; 13/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Callbacky 1 Button_Callback.Connect (Global_Window.all.Quit_Button, 3 "clicked", Button_Callback.To_Marshaller (On_Quit_Button_Clicked’Access), 5 False); -- XXX: window delete event should be also handled, but for simplicity 7 -- reasons, it is ommitted. 9 Button_Callback.Connect (Global_Window.all.Run_Button, 11 "clicked", Button_Callback.To_Marshaller (On_Run_Button_Clicked’Access), 13 False); 14/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Synchronizace mezi GUI vláknem a počítacím vláknem protected Counter_Monitor is 2 procedure Start; entry Wait_For_Start; 4 procedure Stop; function Check_If_Stop return Boolean; 6 procedure Quit; function Check_If_Quit return Boolean; 8 procedure Finished; function Check_If_Running return Boolean; 10 entry Wait_Until_Finished; private 12 Should_Start : Boolean := False; Should_Stop : Boolean := False; 14 Should_Quit : Boolean := False; Is_Running : Boolean := False; 16 end Counter_Monitor; 15/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda Synchronizace mezi GUI vláknem a počítacím vláknem 1 protected body Counter_Monitor is procedure Start is 3 begin Should_Start := True; 5 end Start; 7 entry Wait_For_Start when Should_Start or Should_Quit is 9 begin Should_Start := False; 11 Should_Stop := False; -- don’t touch Should_Quit, so that it’s persistant 13 Is_Running := True; end Wait_For_Start; 16/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Gtk http://www.gnu.org/software/guile-gnome/docs/gdk/ html/Threads.html 17/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Asynchronní předávání do GUI 18/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Asynchronní předávání do GUI Strategie 1. vytvoříme smyčku obsluhy událostí GUI, která volá přímo jednotlivé callbacky 2. vlákno, které chce aktualizovat GUI předá práci GUI smyčce 3. do vlákna zpracovávajícího události můžeme zasílat blokujícím (Request) nebo neblokujícím (Send) způsobem Problémy ◾ ověření, že při všech aktualizacích GUI používáme předání práce GUI vláknu 19/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda a Gtk.Main.Router GtkAda Contributions: http://www.dmitry-kazakov.de/ada/gtkada_ contributions.htm Inicializace Vytvoření smyčky událostí ◾ není třeba podpora vláken z Gdk Gtk.Main.Set_Locale; 2 Gtk.Main.Init; Gtk.Main.Router.Init; 4 Init_GUI; Gtk.Main.Main; 6 return; 20/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda a Gtk.Main.Router Zasílání z vlákna o smyčky událostí 1 task body Counter is begin 3 Main_Loop : loop 5 Counter_Monitor.Wait_For_Start; -- if we don’t exit here when appropriate, the application would 7 -- deadlock: the GUI task callback is waiting for us while we’re -- synchronously calling modification of the GUI 9 exit Main_Loop when Counter_Monitor.Check_If_Quit; Gtk.Main.Router.Request (+Update_GUI_Button_Start’Access); 11 Counter_Loop : for I in 0 .. 1000 loop 13 exit Main_Loop when Counter_Monitor.Check_If_Quit; if Counter_Monitor.Check_If_Stop then 15 exit Counter_Loop; end if; 21/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda a Gtk.Main.Router Zasílání z vlákna o smyčky událostí declare 2 Label : aliased Unbounded_String := To_Unbounded_String (Integer’ begin 4 Update_GUI_Label_Callback.Request (Update_GUI_Label’Access, Label end; 6 delay 1.0; end loop Counter_Loop; 8 declare NR : aliased Null_Record; 10 begin -- this goes asynchronously 12 Update_GUI_Button_End_Handler.Send (Update_GUI_Button_End’Access, NR end; 14 Counter_Monitor.Finished; end loop Main_Loop; 16 Counter_Monitor.Finished; end Counter; 22/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda a Gtk.Main.Router Registrace volání ◾ generika ◾ komplikované kvůli typům 1 procedure Update_GUI_Button_Start is begin 3 Gtk.Button.Set_Label (Global_Window.all.Run_Button, -" Stop "); end Update_GUI_Button_Start; 5 type Null_Record is null record; 7 procedure Update_GUI_Button_End (NR : in out Null_Record) is pragma Unreferenced (NR); 9 begin Global_Window.all.Run_Button.all.Set_Label (-" Run "); 11 Global_Window.all.Run_Button.all.Set_Sensitive (True); end Update_GUI_Button_End; 13 procedure Update_GUI_Label (Label_Access : access Unbounded_String) is 15 begin Gtk.Label.Set_Label (Global_Window.all.Counter_Label, -To_String (Label_Ac 17 end Update_GUI_Label; 23/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní GtkAda a Gtk.Main.Router Registrace volání ◾ generika ◾ komplikované kvůli typům 1 -- this is ugly type Local_Callback is access procedure; 3 function "+" is new Ada.Unchecked_Conversion (Local_Callback, Gtk.Main.Router.Gtk_Callback 5 -- this is better 7 package Update_GUI_Label_Callback is new Gtk.Main.Router.Generic_Callback_Req 9 package Update_GUI_Button_End_Handler is new Gtk.Main.Router.Generic_Message 24/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Java SWING Multiplatformní GUI v Javě SWING single-thread rule ◾ všechny prvky mohou být vytvářeny, měněny a dotazovány pouze z vlákna obsluhujícího události ◾ SwingUtilities.isEventDispatchThread – kontrola, zda jsme ve vlákně obsluhující události ◾ SwingUtilities.invokeLater – předávání Runnable do vlákna obsluhujícího události ◾ SwingUtilities.invokeAndWait – předávání Runnable do vlákna obsluhujícího události a zablokuje se do dokončení akce ◾ callbacky se řeší pomocí akcí action listener z vlákna obsluhujícího události ◾ dlouho běžící callbacky je možno odštípnout do nového vlákna (přímo nebo přes Executory) 25/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Java SWING Inicializace 1 public class JavaGUI { 3 public static void main(String[] args) { CounterDialog dialog = new CounterDialog(); 5 dialog.setSize(400,300); dialog.setVisible(true); 7 } 9 } 26/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Java SWING Předávání vláknu událostí SWINGu @Override 2 public void run() { for (int i = 0; i <= 1000; i++) { 4 if (shouldShutdown.get()) { break; 6 } final String labelText = String.valueOf(i); 8 javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { 10 counterLabel.setText(labelText); } 12 }); try { 14 Thread.sleep(1000); } catch (InterruptedException ignored) { 16 } } 18 runButton.setText("Run"); runButton.setEnabled(true); 20 } 27/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Java SWING Callbacky 1 buttonRun.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { 3 onRun(); } 5 }); private void onRun() { 2 if (!isRunning.get()) { buttonRun.setText("Stop"); 4 isRunning.set(true); if (counterThread != null) { 6 try { counterThread.join(); 8 } catch (InterruptedException ignored) { } 10 } counterThread = new CounterThread(counterLabel, buttonRun); 12 counterThread.start(); } else { 14 buttonRun.setEnabled(false); counterThread.requestShutdown(); 16 counterThread.interrupt(); isRunning.set(false); 18 } } 28/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní QT http://doc.trolltech.com/4.7/threads.html rozlišování reentrant vs. thread-safe QThread reprezentuje vlákno QObject je reentrantní, stejně jako řada odvozených tříd avšak odvozené GUI třídy QWidget reentrantní nejsou! ◾ použití pouze z hlavního vlákna per-thread event loop ◾ pro třídy jako QTimer, QTcpSocket – ne pro GUI 29/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní OpenGL Průmyslový standard specifikující multiplatformní rozhraní pro tvorbu aplikací počítačové grafiky Existuje v řadě verzí od 1.0 po poslední 4.0 Aplikace využívající OpenGL je schopna ±běžet na různém HW ◾ OpenGL podporuje různá rozšíření, která spolu se změnami verzí zhoršují poratabilitu ◾ Aplikace musí umět detekovat co daná platforma nabízí Rasterizaci objektů provádí obvykle HW, existují ale i SW razterizátory (Mesa) 30/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní OpenGL pipeline OpenGL funkce jsou asynchronní OpenGL je stavová Návrh scény provádíme: glBegin( GL_POLYGON ); /* Begin issuing a polygon */ 2 glColor3f( 0, 1, 0 ); /* Set the current color to green */ glVertex3f( -1, -1, 0 ); /* Issue a vertex */ 4 glVertex3f( -1, 1, 0 ); /* Issue a vertex */ glVertex3f( 1, 1, 0 ); /* Issue a vertex */ 6 glVertex3f( 1, -1, 0 ); /* Issue a vertex */ glEnd(); /* Finish issuing the polygon */ Problematické při použití vláken 31/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní OpenGL kontext Kontex OpenGL není zachycen OpenGL specifikací, je tedy implementačně závislý Kontex uchovává stav a další informace pro rasterizér Existují rozšíření OpenGL pro manipulaci s kontexty ◾ WGL – wglCreateContext, wglMakeCurrent, wglDeleteContext ◾ GLX – glXCreateNewContext, glXMakeCurrent, glXDestroyContext ◾ Pozor na použití glXDestroyContext – OpenGL je asynchronní! Pouze jeden kontext může být aktivní v rámci 1 vlákna Kontext je často uložen v TLS 32/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní OpenGL kontext a vlákna S implicitním kontextem ◾ OpenGL na MacOS dovoluje přistup k GL funkcím z více vláken ◾ Windows ohlásí resource busy ◾ Linux (s Nvidia drivery) končí segmentation fault ◾ Obecně je u vláken s implicitním kontextem problém, že kontext má právě master vlákno ◾ Nelze triviálně předat kontext jinému vláknu (zejména u GLX) Různá vlákna si mohou vytvořit svůj kontext ◾ Nemohou pak ale kreslit jednu společnou scénu přímo (lze přes nepřímý rendering do bufferu) ◾ U WGL to často znamená, že každé vlákno kreslí do jiného okna 33/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní OpenGL kontext a vlákna Změna kontextu na jiné než master vlákno ◾ Při použití libSDL triviálně tak, že zavoláme SDL_init() z ne-master vlákne, o zbytek se postará libSDL ◾ Implicitní kontext vytváří GLX rozšíření Xserveru samo o sobě ◾ Jediná cesta pro GLX je reload GLX z vlákna, které má kreslit ◾ Návod lze najít např. ve zdrojových kódech libSDL src/video/x11/SDL_x11gl.c 34/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Futures & TPE v C++ Futures nabízí knihovna libboost http://www.boost.org ◾ Nabízí ± stejná primitiva jako pthread ◾ Navíc nabízí některé pokročilejší nástroje pro vlákna 1 #include #include 3 using namespace std; 5 void hello() 7 { cout << "Pocitam." << endl; 9 } 11 int main(int argc, char* argv[]) { 13 boost::thread thrd(&hello); thrd.join(); 15 return 0; } 35/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Futures & TPE v C++ Futures #include 2 #include #include 4 using namespace std; 6 string hello() 8 { cout << "FT: Pocitam." << endl; 10 sleep(5); cout << "FT: Vypocet hotov." << endl; 12 return "12345"; } 14 int main(int argc, char* argv[]) 16 { boost::packaged_task pt(hello); 18 boost::unique_future fi=pt.get_future(); 20 boost::thread task(boost::move(pt)); cout << "Master: vytvoreno vlakno." << endl; 22 cout << "Master: Cekam na vysledek." << endl; fi.wait(); 24 cout << "Mam vysledek: " << fi.get() << endl; return 0; 26 } 36/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Futures & TPE v C++ Samotná knihovna libboost nemá threadpools http://threadpool.sourceforge.net/ implementuje threadpools v C++ nad libboost 37/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Futures & TPE v C++     Anybody who tells me that STL and especially Boost are stable and portable is just so full of bullshit that it’s not even funny. – Linus Torvalds 38/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Java Native Interfaces Volání nativních metod z Javy Struktura JNI volání /* C */ 2 JNIEXPORT void JNICALL Java_ClassName_MethodName (JNIEnv *env, jobject obj, jstring javaString) 4 { //ziskani nativniho retezce z javaString 6 const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0); ... 8 //nezapomenout uvolnit! (*env)->ReleaseStringUTFChars(env, javaString, nativeString); 10 } 12 // C++ JNIEXPORT void JNICALL Java_ClassName_MethodName 14 (JNIEnv *env, jobject obj, jstring javaString) { 16 //ziskani nativniho retezce z javaString const char *nativeString = env->GetStringUTFChars(javaString, 0); 18 ... //nezapomenout uvolnit! 20 env->ReleaseStringUTFChars(javaString, nativeString); } 39/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI Ukazatel na JNIEnv je platný pouze z vlákna, jemuž je přiřazen ◾ nelze předávat mezi vlákny ◾ stejný při opakovaných voláních v témže vlákně Lokální reference nesmí opustit vlákno ◾ lokální reference jsou platné pouze v rámci daného volání nelze se je uschovávat ve static proměnných ◾ převést na globální, pokud je třeba (NewGlobalRef) ◾ globální reference vylučují objekt z garbage collection ◾ existují slabé lokální reference (NewWeakGlobalRef) umožňují garbage collection odkazovaného objektu potřeba kvůli class unloading musí se kontrolovat, zda odkazovaný objekt existuje (IsSameObject s NULL parametrem) 40/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI static jclass stringClass = NULL; 2 ... if (stringClass == NULL) { 4 jclass localRefCls = (*env)->FindClass(env, "java/lang/String"); 6 if (localRefCls == NULL) { return NULL; /* exception thrown */ 8 } /* Create a global reference */ 10 stringClass = (*env)->NewGlobalRef(env, localRefCls); 12 /* The local reference is no longer useful */ (*env)->DeleteLocalRef(env, localRefCls); 14 /* Is the global reference created successfully? */ 16 if (stringClass == NULL) { return NULL; /* out of memory exception thrown */ 18 } } 20 ... // potreba explicitne mazat 22 if (terminate) { (*env)->DeleteGlobalRef(env, stringClass); 24 } Zdroj: JNI Book 41/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI Použití monitorů ◾ vždy monitor uvolnit synchronized (obj) { 2 ... // synchronized block } 1 if ((*env)->MonitorEnter(env, obj) != JNI_OK) ...; ... 3 if ((*env)->ExceptionOccurred(env)) { ... /* exception handling */ 5 /* remember to call MonitorExit here */ if ((*env)->MonitorExit(env, obj) != JNI_OK) ...; 7 } ... /* Normal execution path. */ 9 if ((*env)->MonitorExit(env, obj) != JNI_OK) ...; Zdroj: JNI Book 42/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI Wait/Notify ◾ generické volání metod (GetMethodID, CallVoidMethod) ◾ potřeba držet monitor 1 /* precomputed method IDs */ static jmethodID MID_Object_wait; 3 static jmethodID MID_Object_notify; static jmethodID MID_Object_notifyAll; 5 void 7 JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout) { (*env)->CallVoidMethod(env, object, MID_Object_wait, timeout); 9 } 11 void JNU_MonitorNotify(JNIEnv *env, jobject object) { 13 (*env)->CallVoidMethod(env, object, MID_Object_notify); } 15 void 17 JNU_MonitorNotifyAll(JNIEnv *env, jobject object) { (*env)->CallVoidMethod(env, object, MID_Object_notifyAll); 19 } Zdroj: JNI Book 43/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI Explicitní získání JNIenv pro stávající vlákno ◾ např. callback volaný OS ◾ odkaz na JavaVM lze předávat mezi voláními a vlákny ◾ získání odkazu např. JNI_GetCreatedJavaVMs nebo GetJavaVM 1 JavaVM *jvm; /* already set */ 3 f() { JNIEnv *env; 5 (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL); ... /* use env */ 7 } Zdroj: JNI Book 44/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Vlákna a JNI Mapování vláknového modelu OS a JVM ◾ záleží, zda pro danou platformu JVM podporuje nativní vlákna ◾ závisí od dané platformy i od daného JVM Můžeme implementovat v Javě afinitu k CPU ◾ závisí od dané platformy i od daného JVM ◾ sched_setaffinity(gettid(), ...) ◾ v praxi může pro danou platformu dobře fungovat 45/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Systémy real-time (RT) Požadavky na RT systémy ◾ reakce programu v definovaném termínu (deadline) ◾ hard real-time: systém musí vždy reagovat do deadline ◾ real real-time: hard-RT s velmi krátkou reakční dobou (řízení střel) ◾ soft real-time: systém může občas zmeškat deadline ◾ firm real-time: soft-RT, kdy opožděne poskytovanou službu už nemá smysl poskytovat Interakce s OS ◾ real-time OS ◾ embedded bez OS Paralelismus ◾ většinou se pracuje se sekvenčními programy ◾ co když paralelismus potřebujeme? 46/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Ada: vlákna a RT systémy Zajímavé úrovně jazyka ◾ zero footprint (ZFP): bez vláken (např. jednodušší certifikace pro DO-178B Level A) ◾ Ravenscar profile: omezené interakce vláken (lze lépe dělat statickou analýzu kódu) ◾ plnohodnotný přístup k vláknům Ada Annex D: Real-Time Systems ◾ podpora monotónních hodin s vysokým rozlišením ◾ politiky spouštění vláken (task dispatching) ◾ priority vláken vč. dynamických priorit ◾ politiky řazení do front entries ◾ (preemtivní abort) ◾ synchronní řízení vláken ◾ asynchronní řízení vláken ◾ omezení vláken (pragma Restrictions) Ada Annex H: High-Integrity Systems, Ada 2005 Annex M: Summary of Documentation Requirements, jazyk SPARK 47/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Plánování vláken Plánování ◾ nalezení takového pořadí vykonávání úloh, aby byly splněny termíny ◾ analýza plánovatelnosti Typické úlohy v RT systémech ◾ periodické – opakované v pravidelných intervalech (delay until ...;) ◾ sporadické – reakce na události (typicky čekající pomocí blokování na chráněném objektu) 48/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Preemptive Fixed Priority Dispatching Podpora i před Ada 2005 Task dispatching ◾ proces výběru vlákna, které má běžet na daném procesoru Dispatching points ◾ místa v kódu, kde dochází k přepínání ◾ vždy: blokování na volání, ukončování úlohy ◾ další místa jsou definována annexem pro specifické politiky (např. delay 0.0; pro nepreemtivní plánování) pragma Task_Dispatching_Policy(FIFO_Within_Priorities); ◾ nastavuje se per partition (Distributed Annex) 49/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Preemptive Fixed Priority Dispatching Priorita ◾ definuje fronty, z nichž se odebírají úlohy v případě výběru ◾ vybírá se ze začátku nejprioritnější neprázdné fronty ◾ systém musí podporovat: minimálně 30 úrovní System.Priority minimálně 1 úroveň System.Interrupt Priority Dispatching points specificky pro Preemptive Fixed Priority Dispatching ◾ kdykoli se objeví spustitelné (runnable) vlákno s vyšší prioritou ⇒ preemtpivita ◾ kdykoli se v kódu objeví delay 0.0; 50/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Priority ceiling locking Potřeba minimalizovat dobu čekání prioritních vláken/tasků Motivace: vlákna s prioritami H > M > L, chráněný objekt P 1. spustí se úloha L a vstoupí do P 2. M přeruší vykonávání L, zatímco je L uvnitř P 3. H přeruší vykonávání M 4. H se pokusí vstoupit do P 51/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Priority ceiling locking 13.3 Priority ceiling locking 323 Execution Executing holding resource Preempted Not runnable Blocked waiting for resource Prioirity inversion here Request resource Acquire resource Release resourceAcquire resource time task L M H Fig. 13.1: Priority inversion Definition: Priority inversion occurs when the priority ordering has been subverted – a high-priority task is kept from executing by a low-priority task that is running. ⇒ inverze priorit (M efektivně zabraňuje dokončení H) Zdroj: Burns & Wellings: Concurrent and Real-Time Programming in Ada 52/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Priority ceiling locking Strop priority (priority ceiling) ◾ Immediate Ceiling Priority Protocol (ICPP) neboli Ceiling Priority Emulation neboli Priority Protect Protocol ◾ maximální priorita, s níž mohou být daná úloha či chráněný objekt volány ◾ při vstupu do volání úloha získá úloha stropní prioritu ◾ po ukončení volání se úloha vrátí ke své původní prioritě ◾ jsou-li fakticky zavolány s vyšší prioritou než je strop, je to považováno za chybu programu pragma Locking_Policy(Ceiling_Locking); 53/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Priority ceiling locking Změna chování H/M/L/P systému: 1. spustí se úloha L a vstoupí do P; tím získá prioritu (nejméně) H 2. M je nachystáno, ale nemůže přerušit L protože má nižší okamžitou prioritu 3. H je nachystáno, ale nespustí se, protože nemá vyšší okamžitou prioritu než L 4. L opustí P a je vráceno na původní prioritu 5. H je spuštěno 54/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Priority ceiling locking 324 Scheduling real-time systems – fixed priority dispatching Execution Executing holding resource Preempted Not runnable Blocked waiting for resource Prioirity inversion here Acquire resource Release resource Acquire resource time task L M H Release resource Fig. 13.2: Ceiling priority inheritance priority (that is, its priority is raised – assuming it was lower before the call). The simple three-task system will now behave as follows (see Figure 13.2): Zdroj: Burns & Wellings: Concurrent and Real-Time Programming in Ada 55/55 Vlákna a GUI Futures & TPE v C++ Vlákna a JNI Systémy real-time Ostatní Ostatní Odevzdávání ,,projektu‘‘ ◾ Odevzdavarny/Projekt ◾ UCO-Jmeno-Prijmeni.{zip,tgz,...} Organizace zkoušky ◾ diskuse řešení projektu ◾ minimálně 2 obecné otázky ◾ minimálně 1 specializační (Java/C/Ada)