Rinnakkaisuus Juha Järvensivu juha.jarvensivu@tut.fi 2008
Sisällys Rinnakkaisuus ja käyttöliittymäohjelmointi GUI-thread.NET rinnakkaisuus Asynkroninen delegaatti (.NET) Timerit Backgroundworker (.NET) Java rinnakkaisuus
Responsive GUI Käyttöliittymä ei missään tilanteessa jumiudu, vaan reagoi aina käyttäjän toimintoihin Käyttöliittymän tulee antaa palautetta pitkäkestoisten toimintojen aikana (esim progress bar, wait-animaatio jne) Toiminnon keskeytys
Prosessi vs Säie Prosessi Muistin suojauksen yksikkö Säie Suorituksen yksikkö Prosessi Thread1 Thread2 Thread3 Memory
Sanoman vastaanotto WM_PAINT WM_SIZE Sanomajono WM_DESTROY WM_COMMAND Ohjelma Sanomasilmukka IkkunaProseduuri Sanomakäsittelijä Sanomakäsittelijä Sanomakäsittelijä Sanomakäsittelijä Sanoman oletuskäsittelijä DefWindowProc
GUI-Thread Message queue Main Thread creates Worker thread Worker thread Worker thread
GUI-Thread Message queue Variable use Main Thread creates use Worker thread Worker thread Worker thread
GUI-Thread Message queue Main Thread creates message Worker thread Worker thread Worker thread
.NET rinnakkaisuus
System.Threading Foreground thread Mahdollisuus keskeyttää sovelluksen sulkeminen Ohjelma sulkeutuu vasta kun kaikkien Foregroundtyyppisten säikeiden suoritus on päättynyt. Background thread (daemon thread) Kun ohjelma suljetaan, myös kaikkien Background-säikeiden suoritus lopetaan automaattisesti
Esimerkki Thread secondarythread = new Thread( new ThreadStart(MyThreadProc) ); secondarythread.priority = ThreadPriority.Highest; secondarythread.isbackground = true; secondarythread.start(); static void MyThreadProc() // Säikeessä suoritettava koodi tänne
lock keyword Määrittelee koodilohkon, jonka suoritusta ei voida keskeyttää class WorkerClass public void DoSomeWork() lock(this) // Do some work
System.Threading.Monitor class WorkerClass public void DoSomeWork() try Monitor.Enter(this); // Do some work finally Monitor.Exit(this);
System.Monitor.Interlocked.NET:n aritmeettiset operaatiot eivät ole atomisia operaatioita! int i = 9; lock(this) i++; Interlocked.Increment(ref i);
Delegaatti
Delegaatin kutsuminen synkronisesti class Program public delegate void MyDelegate(); public static void DoWork() for (int i = 0; i < 5; i++) Console.WriteLine("DoWork 0",i); Thread.Sleep(1000); static void Main(string[] args) MyDelegate d = new MyDelegate(DoWork); d(); Console.WriteLine("Done invoking delegate");
Asynkroninen delegaatti class Program public delegate void MyDelegate(); public static void DoWork() for (int i = 0; i < 5; i++) Console.WriteLine("DoWork 0",i); Thread.Sleep(1000); static void Main(string[] args) MyDelegate d = new MyDelegate(DoWork); IAsyncResult itfar = d.begininvoke(null, null); Console.WriteLine("Done invoking delegate "); int result = d.endinvoke(itfar); Console.WriteLine( delegate done");
Asynkroninen delegaatti class Program public delegate void MyDelegate(); public static void DoWork() for (int i = 0; i < 5; i++) Console.WriteLine("DoWork 0",i); Thread.Sleep(1000); public static void DoWorkCallback(IAsyncResult iftar) Console.WriteLine("delegate done"); static void Main(string[] args) MyDelegate d = new MyDelegate(DoWork); d.begininvoke(new AsyncCallback(DoWorkCallback), null); Console.WriteLine("Done invoking delegate "); // Estetään sovelluksen loppuminen Console.ReadLine();
Invoke-mekanismi
Control.Invoke Mahdollistaa UI-komponentin metodin kutsumisen toisesta säikeestä Toteutettu delegate mekanismin avulla Parametrina annettua delegaattifunktiota kutsutaan säikeestä, joka omistaa UIkomponentin
Virheellinen esimerkki! void StartThread() // Käynnistetään uusi säie Thread t = new Thread(new ThreadStart(DoSomeWork)); t.start(); void DoSomeWork() this.label1.text = Tehtävä valmis. Väärin!
Esimerkki private delegate void InvokeDelegate(); void StartThread() // Käynnistetään uusi säie Thread t = new Thread(new ThreadStart(DoSomeWork)); t.start(); private void Notify() this.label1.text = Tehtävä valmis. ; void DoSomeWork() // Toisessa säikeessä suoritettava koodi InvokeDelegate n = new InvokeDelegate(Notify); label1.invoke(n); Oikein
Timers System.Windows.Forms.Timer Windows based timer System.Timers.Timer Server based timer System.Threading.Timer Thread timers
System.Windows.Forms.Timer Toimii kuten UI-komponentit ja tarvitsee toimiakseen ikkunan (form) Toiminta perustuu sanomien käyttöön Suunniteltu single-thread ympäristöön
System.Timers.Timer Ajetaan eri säikeessä kuin UI käytä invoke mekanismia UI-komponenttien päivittämiseen private System.Timers.Timer t = new Timer(); t.elapsed += new ElapsedEventHandler(t_Elapsed); void t_elapsed(object sender, ElapsedEventArgs e) InvokeDelegate n = new InvokeDelegate(Notify); label1.invoke(n); private void Notify() this.label1.text = "" + c1.value;
Background worker The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution. Lähde: MSDN
Esimerkki private void InitializeBackgoundWorker() backgroundworker1.dowork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundworker1.runworkercompleted += new RunWorkerCompletedEventHandler( backgroundworker1_runworkercompleted); backgroundworker1.progresschanged += new ProgressChangedEventHandler( backgroundworker1_progresschanged);
DoWork // This event handler is where the actual, // potentially time-consuming work is done. private void backgroundworker1_dowork(object sender, DoWorkEventArgs e) // Get the BackgroundWorker that raised this event. BackgroundWorker worker = sender as BackgroundWorker; // Assign the result of the computation // to the Result property of the DoWorkEventArgs // object. This is will be available to the // RunWorkerCompleted eventhandler. e.result = ComputeFibonacci((int)e.Argument, worker, e);
WorkCompleted // This event handler deals with the results of the background operation. private void backgroundworker1_runworkercompleted( object sender, RunWorkerCompletedEventArgs e) // First, handle the case where an exception was thrown. if (e.error!= null) MessageBox.Show(e.Error.Message); else if (e.cancelled) resultlabel.text = "Canceled"; else resultlabel.text = e.result.tostring();
ProgressChanged // This event handler updates the progress bar. private void backgroundworker1_progresschanged(object sender, ProgressChangedEventArgs e) this.progressbar1.value = e.progresspercentage; Long ComputeFibonacci( ) //... worker.reportprogress(percentcomplete); //
Java rinnakkaisuus
Thread-luokka class PrimeThread extends Thread long minprime; PrimeThread(long minprime) this.minprime = minprime; public void run() // compute primes larger than minprime... // The following code create a thread and start it PrimeThread p = new PrimeThread(143); p.start(); http://java.sun.com/j2se/1.4.2/docs/api/java/lang/thread.html
Runnable-rajapinta class PrimeRun implements Runnable long minprime; PrimeRun(long minprime) this.minprime = minprime; public void run() // compute primes larger than minprime... // The following code create a thread and start it PrimeRun p = new PrimeRun(143); new Thread(p).start(); http://java.sun.com/j2se/1.4.2/docs/api/java/lang/thread.html
Synchronized Synchronized Methods public synchronized void increment() c++; Synchronized statements public void addname(string name) synchronized(this) lastname = name; namecount++; namelist.add(name);
Single thread rule The single-thread rule: Swing components can be accessed by only one thread at a time. Generally, this thread is the eventdispatching thread
Exception to the rule An application's GUI can often be constructed and shown in the main thread public class MyApplication public static void main(string[] args) JFrame f = new JFrame("Labels"); // Add components to // the frame here... f.pack(); f.show(); // Don't do any more GUI work here...
Exception to the rule The following JComponent methods are safe to call from any thread Repaint() Revalidate() Invalidate()
Exception to the rule Listener lists can be modified from any thread addlisterner() removelistener()
Event dispacthing rule Event dispatching: If you need access to the UI from outside event-handling or drawing code, then you can use the SwingUtilities invokelater()or invokeandwait() method.
invokelater Requests that some code be executed in the event-dispatching thread. Runnable doworkrunnable = new Runnable() public void run() dowork(); ; SwingUtilities.invokeLater(doWorkRunnable);
Hello.java (GUI) import javax.swing.*; public class HelloWorldSwing private static void createandshowgui() JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("HelloWorldSwing"); frame.setdefaultcloseoperation(jframe.exit_on_close); JLabel label = new JLabel("Hello World"); frame.getcontentpane().add(label); frame.pack(); frame.setvisible(true); public static void main(string[] args) javax.swing.swingutilities.invokelater(new Runnable() public void run() createandshowgui();
Lähteet System.Threading http://msdn2.microsoft.com/enus/library/system.threading.aspx Threading (C# programming guide) http://msdn2.microsoft.com/en-us/library/ms173178.aspx P/Invoke http://msdn.microsoft.com/msdnmag/issues/03/07/net/ BackgroundWorker http://msdn2.microsoft.com/enus/library/system.componentmodel.backgroundworker.aspx
Lähteet Asynchronous Delegates http://msdn.microsoft.com/library/default.asp?url=/libr ary/enus/cpguide/html/cpovrasynchronousdelegates.asp Control.Invoke http://msdn2.microsoft.com/enus/library/zyzhdc6b.aspx Swing threads http://java.sun.com/products/jfc/tsc/articles/threads/thr eads1.html http://java.sun.com/products/jfc/tsc/articles/threads/thr eads2.html