1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[220446] Updated the "DSF Common Patterns" document.

This commit is contained in:
Pawel Piech 2008-03-01 00:43:50 +00:00
parent 14259c32e5
commit 86e9c84f41
8 changed files with 837 additions and 159 deletions

View file

@ -0,0 +1,837 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>DSF Common Patterns</title>
</head>
<body>
<h2 style="text-align: center;">DSF Common Patterns<br>
</h2>
<h4>Summary</h4>
<h3>Examples<br>
</h3>
Running example code is and performing included excercises is very
helpful in following this tutorial.&nbsp; In order to run the examples
in this tutorial the following is needed:<br>
<ol>
<li>Download and install Eclipse development environment, either the <span
style="font-style: italic;">Eclipse Classic 3.4 </span>or <span
style="font-style: italic;">Eclipse IDE for C/C++ Developers</span><br>
</li>
<li>Install the DSF SDK feature to build against, by performing
either:<br>
</li>
<ol style="list-style-type: lower-alpha;">
<li>Using update manager, install the <span
style="font-style: italic;">Debugger Services Framework end-user and
extender SDK</span>, found in the <span style="font-style: italic;">Ganymede
Discovery Site</span> under <span style="font-style: italic;">Remote
Access and Device Development</span>.</li>
<li>Check out <span style="font-style: italic;">org.eclipse.dd.dsf
and org.eclipse.dd.dsf.ui</span> plugins, found in the <span
style="font-style: italic;">/cvsroot/dsdp</span> repository under <span
style="font-style: italic;">org.eclipse.dd.dsf/plugins</span>
directory.</li>
</ol>
<li>Check out the <span style="font-style: italic;">org.eclipse.dd.examples.dsf</span>
plugin, found <span style="font-style: italic;">/cvsroot/dsdp</span>
under <span style="font-style: italic;">org.eclipse.dd.dsf/plugins</span>
directory.</li>
<li>Build the examples plugin:</li>
<ol style="list-style-type: lower-alpha;">
<li>Execute the build the first time to build and run the
excercises preprocessor.</li>
<li>Refresh the resources in the plugin (right-click on project in <span
style="font-style: italic;">Navigator</span> and select <span
style="font-style: italic;">Refresh</span>), in order to recognize the
sources generated by the preprocessor.</li>
<li>Build the plugin again to compile the generated sources.</li>
</ol>
<li>Launch the examples</li>
<ol style="list-style-type: lower-alpha;">
<li>Examples in data org.eclipse.dd.examples.dsf.requestmonitor and
org.eclipse.dd.examples.dsf.dataviewer packages each contain a public
main() function.&nbsp; They can be launched using the Java Application
launch type.</li>
<li><span style="color: rgb(255, 0, 0);">TODO: Launching timers
example</span></li>
</ol>
</ol>
<h3>Asynchronous Methods</h3>
One of the central features of DSF is that it relies very heavily on
the use of asynchronous methods.&nbsp; <span
style="font-style: italic;">Asynchronous methods</span> here mean
simply methods that <span style="font-weight: bold;">use a callback
object to indicate their completion</span>. The use of asynchronous
methods can be very contageous in a system, where if a lower level API
is composed of asynchronous methods, a higher level system which uses
those methods also has to have asynchronous methods in its interface
(or risk blocking its calling thread).<br>
<br>
<span style="font-style: italic; color: rgb(255, 0, 0);">TODO? :
diagram of a layered system with asynchronous APIs</span><br>
<h4>Request Monitor</h4>
There is a standard callback object used in DSF, the request
monitor.&nbsp; A request monitor has the following features:<br>
<ul>
<li><span style="text-decoration: underline;">Executor</span> - A
argument to the request monitor constructor allows the user to specify
what executor should be used to invoke the callback method.&nbsp; <br>
</li>
<li><span style="text-decoration: underline;">Status</span> -
Asynchronous methods that take a callback can always set the status
indicating the success or failure of the call.</li>
<li><span style="text-decoration: underline;">Callback Methods</span>
- The request monitor declares several protected methods which are
invoked when the callback is invoked: handleCompleted(), handleOK(),
handleError(), etc.&nbsp; The users may override these methods as
needed to perform additional processing upon asynchronous method
completion.</li>
<li><span style="text-decoration: underline;">Parent Request Monitor</span>
- If the method calling an asynchronous method is itself asynchronous,
it may set its argument request monitor as the parent of the request
monitor it is creating.&nbsp; The parent request monitor will be <br>
automatically invoked when the lower level request monitor is completed.</li>
</ul>
Following is the snippet from a the
"hello world" example of using a
request monitor:<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.requestmonitor.AsyncHelloWorld</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line26"> 26: </a><strong><font color="#4169e1"><a
name="AsyncHelloWorld"></a>public class AsyncHelloWorld </font></strong>{<br><br><a
name="line28"> 28: </a><strong><font color="#4169e1"> public static void main(String[] args)</font></strong> {<br><a
name="line29"> 29: </a> Executor executor = ImmediateExecutor.getInstance();<br><a
name="line30"> 30: </a> RequestMonitor rm = new RequestMonitor(executor, null);<br><a
name="line31"> 31: </a> asyncHelloWorld(rm);<br><a name="line32"> 32: </a> }<br><br><a
name="line34"> 34: </a> static void asyncHelloWorld(RequestMonitor rm) {<br><a
name="line35"> 35: </a> System.out.println(<font color="#666666">"Hello world"</font>);<br><a
name="line36"> 36: </a> rm.done();<br><a name="line37"></a> 37: <span
style="font-family: sans-serif;"></span><a name="line37"></a>}</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>
</p>
<ul>
<li><a name="line37">Line 29 creates an "immediate executor".&nbsp;
Unlike more
sophisticated executors, the immediate executor simply invokes the
runnable it receives immediately.&nbsp; It does not use any threads and
it will never throw a RejectedExecutionException.</a></li>
<a name="line37"> </a>
<li>Line 30 creates the request monitor.&nbsp; This
program does not
perform any processing after the callback is invoked, so it does not
override RequestMonitor's completion methods.</li>
<li>Line 36 marks the callback as completed and
implicilty invokes
the callback method.&nbsp; As a contract with the caller, the
asynchronous method has to invoke done() when its finished.&nbsp; As
there is no compiler support for ensuring that the asynchronous method
completes the request monitor,&nbsp; failure to do so results in common
but often suble and difficult to track down bug</li>
</ul>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);"><span
style="text-decoration: underline;">Excercise 1</span>: A common
problem in DSF is implementing nested asynchronous methods, this
excercise adds a second-level asynchronous method to
AsyncHelloWorld.&nbsp; <br>
<p style="font-style: italic;">Look
for comments preceeded with "// TODO Excercise 1" in the
org.eclipse.dd.examples.dsf.requestmonitor.AsyncHelloWorld
module.</p>
</td>
</tr>
</tbody>
</table>
<br>
<h4>Data Request Monitor</h4>
The base request monitor is useful for returning
status of the
asynchronous method, but they do not have an option of returning a
value to the caller.&nbsp; DataRequestMonitor can be used for that
purpose. A simple example of using the data request monitor:<br>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.requestmonitor.Async2Plus2</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line22"> 22: </a><strong><font color="#4169e1"><a
name="Async2Plus2"></a>public class Async2Plus2 </font></strong>{<br><a
name="line23"> 23: </a> <br><a name="line24"> 24: </a><strong><font
color="#4169e1"> public static void main(String[] args)</font></strong> {<br><a
name="line25"> 25: </a> Executor executor = ImmediateExecutor.getInstance();<br><a
name="line26"> 26: </a> DataRequestMonitor&lt;Integer&gt; rm = <br><a
name="line27"> 27: </a> new DataRequestMonitor&lt;Integer&gt;(executor, null) {<br><a
name="line28"> 28: </a> @Override<br><a name="line29"> 29: </a><strong><font
color="#4169e1"> protected void handleCompleted()</font></strong> {<br><a
name="line30"> 30: </a> System.out.println(<font
color="#666666">"2 + 2 = "</font> + getData());<br><a name="line31"> 31: </a> }<br><a
name="line32"> 32: </a> };<br><a name="line33"> 33: </a> asyncAdd(2, 2, rm);<br><a
name="line34"> 34: </a> }<br><br><a name="line36"> 36: </a> static void asyncAdd(int value1, int value2, DataRequestMonitor&lt;Integer&gt; rm) {<br><a
name="line37"> 37: </a> rm.setData(value1 + value2);<br><a
name="line38"> 38: </a> rm.done();<br><a name="line39"> 39: </a> }<br><a
name="line40"> 40: </a>}<br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>Lines 26-27 create the data request monitor using a local class
declaraion.&nbsp; Note the type parameter to DataRequestMonitor allows
for compiler checking of the type when calling getData() and setData()
methods.</li>
<li>Lines 29-31 override the standard callback to print the result of
the calculation to the console.<br>
</li>
</ul>
<h4>Multi-Request Monitor</h4>
A common problem when using asynchronous is that several asynchronous
methods need to be called in parallel, so the calling method needs to
somehow manage the completion of several request monitors.&nbsp;
CountingRequestMonitor can be used for this purpose.&nbsp; It is
configured such that it's done() method needs to be called a <span
style="font-style: italic;">count</span> number of times before the
callback method is invoked.&nbsp; <br>
The following snipped from the AsyncQuicksort example shows a simple
example of using the CountingRequestMonitor:<br>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.requestmonitor.AsyncQuicksort.asyncQuickSort()</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line42"> 42: </a> static void asyncQuicksort(final int[] array, final int left, <br><a
name="line43"> 43: </a> final int right, final RequestMonitor rm) <br><a
name="line44"> 44: </a> {<br><a name="line45"> 45: </a> <font
color="#4169e1">if</font> (right &gt; left) {<br><a name="line46"> 46: </a> int pivot = left;<br><a
name="line47"></a><a name="line48"> 48: </a> int newPivot = partition(array, left, right, pivot);<br><a
name="line49"> 49: </a> printArray(array, left, right, newPivot);<a
name="line50"><br><br></a><a name="line51"> 51: </a> CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);<br><a
name="line52"> 52: </a> asyncQuicksort(array, left, newPivot - 1, countingRm);<br><a
name="line53"> 53: </a> asyncQuicksort(array, newPivot + 1, right, countingRm);<br><a
name="line54"> 54: </a> countingRm.setDoneCount(2);<br><a
name="line56"> 55: </a> } <font color="#4169e1">else</font> {<br><a
name="line57"> 56: </a> rm.done();<br><a name="line58"> 57: </a> }<br><a
name="line59"> 58: </a> }<br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>Line 50 creates the CountingRequestMonitor.&nbsp; Note that the
parent request monitor is set to the request monitor from the
asyncQuicksort() argument.&nbsp; This parent request monitor is
automatically called when the counting request monitor is completed.</li>
<li>Lines 51 and 52, use the same instance of counting request
monitor when calling the sub-routine.&nbsp; Each sub-routine will call
done() on the counting request monitor.</li>
<li>Line 53 sets the count to the number of sub-routines called with
the counting request monitor.&nbsp; Note that the done count can be set
after calling the sub-routines, because the counting request monitor
will not be completed until the count is set. <br>
</li>
<li>Line 55 Don't forget to complete the request monitor in all
execution paths!</li>
</ul>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);"><span
style="text-decoration: underline;">Excercise 2</span>: Converting a
synchronous method into an asynchronous one, is another common task in
DSF.&nbsp; This excercise converts the AsyncQuicksort.partition()
method into asynchronous AsyncQuicksort.asyncPartition().&nbsp; <br>
<p><span style="font-style: italic;">Look
for comments preceeded with "// TODO Excercise 2" in the
org.eclipse.dd.examples.dsf.requestmonitor.AsyncQuicksort
module.</span></p>
</td>
</tr>
</tbody>
</table>
<h3>Concurrency</h3>
The simple examples in previous section used asynchronous method
signatures, however no real asynchronous work was performed since all
execution was performed in the main thread.&nbsp; This section examines
a more typical example of a problem that DSF is intended to solve: a
viewer and an asynchronous data generator.<br>
<p>The IDataGenerator interface contains the following two asynchronous
data access methods:<br>
</p>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.dataviewer.IDataGenerator</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line48"></a><a name="line49"> 49: </a> void getCount(DataRequestMonitor&lt;Integer&gt; rm);<br><a
name="line50"> 50: </a> void getValue(int index, DataRequestMonitor&lt;String&gt; rm); <br><a
name="line59"></a></pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>The example is intended to simulate a realistic problem therefore,
it
can be assumed that these methods do not complete the request monitor
immediately, but rather that the requests are completed on a separate
thread and with some delay.&nbsp; There are two implementations of this
service provided:</p>
<ol>
<li>DataGeneratorWithThread - Uses a java thread directly and various
synchronization mechanisms for data integrity.<br>
</li>
<li>DataGeneratorWithExecutor - Uses a DSF executor for both
asynchronous execution and synchronization.</li>
</ol>
There are also two viewers provided which display data from the data
generator:<br>
<ol>
<li>SyncDataViewer - Table-based viewer which implements a
synchronous IStructuredContentProvider interface.<br>
</li>
<li>AsyncDataViewer - Table-based viewer which implements an
asynchronous ILazyContentProvider interface.</li>
</ol>
<h4>Query</h4>
DSF is designed to facilitate use of asynchronous APIs.&nbsp; However,
sometimes there are situations where a synchronous method has to be
implemented to call an asynchronous method.&nbsp; One utility used to
accomplish this is a DSF Query object.&nbsp; The Query object is meant
to be extended by clients in order to override the asynchronous
execute() method. The client code using a query can use the execute()
implementation in order to call other asynchronous methods.&nbsp; The
following snippet
from SyncDataViewer.getElements()&nbsp; shows the use of Query:<br>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.</span><span
style="font-family: monospace; font-weight: bold;">dataviewer.SyncDataViewer.getElements()</span>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line59"> 59: </a> <font color="#b22222">// Create the query object for reading data count. </font><br><a
name="line60"> 60: </a> Query&lt;Integer&gt; countQuery = new Query&lt;Integer&gt;() {<br><a
name="line61"> 61: </a> @Override<br><a name="line62"> 62: </a> protected void execute(DataRequestMonitor&lt;Integer&gt; rm) {<br><a
name="line63"> 63: </a> fDataGenerator.getCount(rm);<br><a
name="line64"> 64: </a> }<br><a name="line65"> 65: </a> };<br><a
name="line66"> 66: </a> <br><a name="line67"> 67: </a> <font
color="#b22222">// Submit the query to be executed. A query implements a runnable</font><br><a
name="line68"> 68: </a> <font color="#b22222">// interface and it has to be executed in order to do its work.</font><br><a
name="line69"> 69: </a> ImmediateExecutor.getInstance().execute(countQuery);<br><a
name="line70"> 70: </a> int count = 0;<br><a name="line71"> 71: </a> <br><a
name="line72"> 72: </a> <font color="#b22222">// Block until the query completes, which will happen when the request</font><br><a
name="line73"> 73: </a> <font color="#b22222">// monitor of the execute() method is marked done.</font><br><a
name="line74"> 74: </a> <font color="#4169e1">try</font> {<br><a
name="line75"> 75: </a> count = countQuery.get();<br><a
name="line76"> 76: </a> } <font color="#4169e1">catch</font> (Exception e) { <br><a
name="line77"> 77: </a> <font color="#b22222">// InterruptedException and ExecutionException can be thrown here.</font><br><a
name="line78"> 78: </a> <font color="#b22222">// ExecutionException containing a CoreException will be thrown </font><br><a
name="line79"> 79: </a> <font color="#b22222">// if an error status is set to the Query's request monitor.</font><br><a
name="line80"> 80: </a> <font color="#4169e1">return</font> new Object[0]; <br><a
name="line81"> 81: </a> } <br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>Line 60 creates the query object.&nbsp; <br>
</li>
<li>On line 63, inside the execute() method, the asynchronous
getCount() method is called</li>
<li>Line 69 submits the query to an executor.&nbsp; This is very
important, because a Query object simply implements Runnable, it will
not perform the work in its exectute() method unless it is submitted to
an executor.&nbsp; <br>
</li>
<li>Line 75 blocks while calling the
java.util.concurrent.Future.get() method, implemented by Query, until
the request monitor from the execute() method is completed.</li>
</ul>
<table border="0" cellpadding="5" cellspacing="30">
<tbody>
<tr>
<td style="text-align: center; vertical-align: middle;"><img
title="Sequence diagram of Query use in getElements()."
style="width: 418px; height: 478px;" alt="" src="query_1.png"><br>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><small><span
style="font-weight: bold;">Image 1: Sequence diagram of Query use in
getElements().</span></small><br>
</td>
</tr>
</tbody>
</table>
<span style="font-style: italic; color: rgb(255, 0, 0);"></span><br>
<br>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td style="text-align: left;">Note: Using the query object
requires a great deal of care because calling
a blocking method can create performance problems and raises
possibility of deadlock. One common deadlock scenario occurs when
the get() method is being called by a thread which is itself required
for completion of the asynchronous methods called by execute().</td>
</tr>
</tbody>
</table>
<br>
<p style="font-style: italic;"><span style="color: rgb(255, 0, 0);">TODO
?: add a sequence diagram of the deadlock scenario</span><br>
</p>
<p> </p>
<h4>Synchronization</h4>
Managing race conditions and deadlocks is one of the most challanging
problems of large multi-threaded systems.&nbsp; DSF uses a
single-threaded executor as the primary mechanism for safe-guarding
access to data.&nbsp; Methods, which need to access data protected by
the DSF executor, have to access this data inside a runnable submitted
to the executor thread.&nbsp; The following is an example of this from
the DataGeneratorWithExecutor:<br>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.dataviewer.DataGeneratorWithExecutor.addListener()</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line174">174: </a><strong><font color="#4169e1"> public void addListener(final Listener listener)</font></strong> {<br><a
name="line175">175: </a> <font color="#4169e1">try</font> {<br><a
name="line176">176: </a> fExecutor.execute( new DsfRunnable() {<br><a
name="line177">177: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
name="line178">178: </a> fListeners.add(listener);<br><a
name="line179">179: </a> }<br><a name="line180">180: </a> });<br><a
name="line181">181: </a> } <font color="#4169e1">catch</font> (RejectedExecutionException e) {}<br><a
name="line182">182: </a> }<br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>Line 174 declares the addListener() method which can be called on
any thread.</li>
<li>Line 176 submits a local runnable to the DSF executor.</li>
<li>Line 178 accesses the protected data: fListeners.</li>
</ul>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td style="text-align: left;"> <span style="font-style: italic;">Note:
It is immediately apparent that this synchronization mechanism
adds a lot of overhead and for such a simple example, it is much less
efficient than using a synchronized section or an atomic
variable.&nbsp; It
is less obvious how this mechanism adds value, however this document is
just a tutorial so the discussion of the merits of the design will be
left out.</span><br>
</td>
</tr>
</tbody>
</table>
<table border="0" cellpadding="5" cellspacing="30">
<tbody>
<tr>
<td style="text-align: center;"><img
style="width: 195px; height: 294px;" alt=""
title="Synchronization using multiple locks."
src="synchronization_1.png"></td>
<td style="text-align: center; vertical-align: middle;"><img
title="Synchronization using a DSF executor."
style="width: 267px; height: 322px;" alt="" src="synchronization_2.png"><br>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><small><span
style="font-weight: bold;">Image 1: Synchronization using multiple
locks on data.</span></small><br>
</td>
<td style="vertical-align: top;"><small><span
style="font-weight: bold;">Image 2: Synchronization using a single
DSF executor thread.</span></small><br>
</td>
</tr>
</tbody>
</table>
Comparing other parts of the two data generator implementation shows
that using the synchronization mechanism above is the principal
difference between the two implementations.&nbsp; One notable exception
is the principal processing loop in each data generator.&nbsp; In the
thread-based implementation this loop is implemented in the run method
of the generator's thread:<br>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.dataviewer.DataGeneratorWithThread.run()</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line139">139: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
name="line140">140: </a> <font color="#4169e1">try</font> {<br><a
name="line141">141: </a> <font color="#4169e1">while</font>(true) {<br><a
name="line142">142: </a> <font color="#b22222">// Get the next request from the queue. The time-out </font><br><a
name="line143">143: </a> <font color="#b22222">// ensures that that the random changes get processed. </font><br><a
name="line144">144: </a> final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);<br><a
name="line145">145: </a> <br><a name="line146">146: </a> <font
color="#b22222">// If a request was dequeued, process it.</font><br><a
name="line147">147: </a> <font color="#4169e1">if</font> (request != null) {<br><a
name="line148">148: </a> <font color="#b22222">// Simulate a processing delay.</font><br><a
name="line149">149: </a> Thread.sleep(PROCESSING_DELAY);<br><a
name="line150">150: </a> <br><a name="line151">151: </a> <font
color="#4169e1">if</font> (request instanceof CountRequest) {<br><a
name="line152">152: </a> processCountRequest((CountRequest)request);<br><a
name="line153">153: </a> } <font color="#4169e1">else</font> <font
color="#4169e1">if</font> (request instanceof ItemRequest) {<br><a
name="line154">154: </a> processItemRequest((ItemRequest)request);<br><a
name="line155">155: </a> } <font color="#4169e1">else</font> <font
color="#4169e1">if</font> (request instanceof ShutdownRequest) {<br><a
name="line156">156: </a> <font color="#b22222">// If shutting down, just break out of the while(true) </font><br><a
name="line157">157: </a> <font color="#b22222">// loop and thread will exit.</font><br><a
name="line158">158: </a> request.fRequestMonitor.done();<br><a
name="line159">159: </a> <font color="#4169e1">break</font>;<br><a
name="line160">160: </a> }<br><a name="line161">161: </a> }<br><a
name="line162">162: </a> <br><a name="line163">163: </a> <font
color="#b22222">// Simulate data changes.</font><br><a name="line164">164: </a> randomChanges();<br><a
name="line165">165: </a> }<br><a name="line166">166: </a> }<br><a
name="line167">167: </a> <font color="#4169e1">catch</font> (InterruptedException x) {}<br><a
name="line168">168: </a> } <br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>Line 141 creates the loop that runs continuously until the break
statement on line 159.</li>
<li>Line 149 implements the artcificial processing delay that is
executed for each request.</li>
</ul>
<p>In contrast the executor-based generator uses a dedicated method for
servicing the queue, which is called by every method that adds a new
request to the queue:<br>
</p>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.dataviewer.DataGeneratorWithExecutor.serviceQueue()</span>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;">
<pre><a name="line197">197: </a><strong><font color="#4169e1"> private void serviceQueue()</font></strong> {<br><a
name="line198"></a>...<br><a name="line199"></a><a name="line201">201: </a> <font
color="#b22222">// If a queue servicing is already scheduled, do nothing.</font><br><a
name="line202">202: </a> <font color="#4169e1">if</font> (fServiceQueueInProgress) {<br><a
name="line203">203: </a> <font color="#4169e1">return</font>;<br><a
name="line204">204: </a> }<br><a name="line205">205: </a> <br><a
name="line206">206: </a> <font color="#4169e1">if</font> (fQueue.size() != 0) {<br><a
name="line207">207: </a> <font color="#b22222">// If there are requests to service, remove one from the queue and </font><br><a
name="line208">208: </a> <font color="#b22222">// schedule a runnable to process the request after a processing</font><br><a
name="line209">209: </a> <font color="#b22222">// delay.</font><br><a
name="line210">210: </a> fServiceQueueInProgress = true;<br><a
name="line211">211: </a> final Request request = fQueue.remove(0);<br><a
name="line212">212: </a> fExecutor.schedule(<br><a
name="line213">213: </a> new DsfRunnable() {<br><a
name="line214">214: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
name="line215">215: </a> <font color="#4169e1">if</font> (request instanceof CountRequest) {<br><a
name="line216">216: </a> processCountRequest((CountRequest)request);<br><a
name="line217">217: </a> } <font color="#4169e1">else</font> <font
color="#4169e1">if</font> (request instanceof ItemRequest) {<br><a
name="line218">218: </a> processItemRequest((ItemRequest)request);<br><a
name="line219">219: </a> } <br><a name="line220">220: </a> <br><a
name="line221">221: </a> <font color="#b22222">// Reset the processing flag and process next</font><br><a
name="line222">222: </a> <font color="#b22222">// request.</font><br><a
name="line223">223: </a> fServiceQueueInProgress = false;<br><a
name="line224">224: </a> serviceQueue();<br><a
name="line225">225: </a> }<br><a name="line226">226: </a> }, <br><a
name="line227">227: </a> PROCESSING_DELAY, TimeUnit.MILLISECONDS);<br><a
name="line228">228: </a> }<br><a name="line229">229: </a> }<br></pre>
</td>
</tr>
</tbody>
</table>
</div>
<ul>
<li>On line 202, the fServiceQueueInProgress flag is used to ensure
that the queue servicing runnable is not scheduled too often.</li>
<li>Line 211 removes the top request from the queue. <br>
</li>
<li>Line 212 calls the ExecutorService.schedule() method to run the
queue servicing runnable, with a delay that simulates the request
processing time.</li>
<li>Line 224, after servicing runnableis finished, calls
serviceQueue() again to process the next item in the queue.</li>
</ul>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td style="text-align: left;">Note: When using a single-threaded
executor as the synchronization
method very few other synchronization mechanisms need to be used.&nbsp;
For example the DataGeneratorWithExecutor.fQueue member is just a plain
un-synchronized list.&nbsp; This is true even when using background
threads to perform long-running tasks, as long as these background
threads can call a request monitor when finished.<br>
</td>
</tr>
</tbody>
</table>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);"><span
style="text-decoration: underline;">Excercise 3</span>: One benefit of
the single-threaded executor concurrency model is that as long as a
method is guaranteed to run in the executor thread, this method may
access and modify any of the variables protected by this
executor.&nbsp; This excercise demonstrates performing a somewhat more
complicated operation on protected state data.<br>
<p><span style="font-style: italic;">Look
for comments preceeded with "// TODO Excercise 3" in the
org.eclipse.dd.examples.dsf.dataviewer.DataGeneratorWithExcecutor
module.</span></p>
</td>
</tr>
</tbody>
</table>
<h4>Annotations</h4>
In any multi-threaded system it can become very difficult to determine
what are the rules governing access to the various data objects.&nbsp;
In a DSF system, it is even more important to identify which data
objects can only be accessed using a designated DSF executor.&nbsp;
Since there is no Java language mechanisms for this purpose, DSF
defines a number annotations that can be used for this purpose.&nbsp;
The annotations are hierarchical, so that if a class has a given
annotation in its declaration, its members and fields are assumed to
have the same access restriction unless otherwise specified.<br>
<p>DSF synchronization annotations defined in
org.eclipse.dd.dsf.concurrent<br>
</p>
<ul>
<li><span style="text-decoration: underline;">ThreadSafe</span> -
Indicates that the given element can be accessed on any thread.&nbsp;
Typically, if this annotation is used, the given member or class uses
syncrhonized or atomic objects to protect its data.</li>
<li><span style="text-decoration: underline;">Immutable</span> -
Immutable objects cannot be modified after they are created, thus they
are also thread-safe.&nbsp; The easiest way to make an object
immutable, is to declare all its fields final and make sure that its
fields are also immutable.&nbsp; Examples of immutable objects are Java
Strings, primitive object types, etc.</li>
<li><span style="text-decoration: underline;">ConfinedToDsfExecutor(executor)</span>
- Indicates that the given object can only be accessed using the given
executor.&nbsp; The executor parameter is a string (since that's the
only allowable parameter type to annotations), but it should indicate
the executor, using classe's member and method names.</li>
<li><span style="text-decoration: underline;">ThreadSafeAndProhibitedFromDsfExecutor(executor)</span>
- Rarely used, it indicates that the given element can be accessed on
any thread except using the given executor.&nbsp; An example of such a
method would be the SyncDataViewer.getElements() method, which should
never be called using the executor belonging to the data provider.<br>
</li>
</ul>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td style="text-align: left;"> Note: The DSF synchronization
annotations are no more than a comment intended to help make the code
more understandable and maintainable.&nbsp; Unfortunately, since there
is no compiler enforcment of their presence, it is easy to forget to
add them.<br>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);">
<p><span style="text-decoration: underline;">Excercise 4</span>:
This excercise adds the appropriate synchronization annotations to the
methods and fields of DataProviderWithExecutor. <br>
</p>
<p><span style="font-style: italic;">Look
for comments preceeded with "// TODO Excercise 4" in the
org.eclipse.dd.examples.dsf.dataviewer.DataGeneratorWithExcecutor
module.</span></p>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);"><span
style="text-decoration: underline;">Excercise 5</span>: It is all too
easy to get into a deadlock situation.&nbsp; This excercise
purposefully puts the data viewer system into a deadlock.&nbsp; The
deadlock first renders the data viewer unusable, but the main thread
also gets deadlocked when attempting to exit the program.<br>
<p><span style="font-style: italic;">Look
for comments preceeded with "// TODO Excercise 5" in the
org.eclipse.dd.examples.dsf.dataviewer.SyncDataViewer
module.</span></p>
</td>
</tr>
</tbody>
</table>
<h3>Services</h3>
<h4>OSGi</h4>
<h4>Session</h4>
<h4>Tracker</h4>
<h3>Data Model</h3>
<h3>View Model</h3>
<h4>Adapter, Provider, Node</h4>
<h4>Timers</h4>
<br>
<div style="margin-left: 20px;">
<table style="text-align: left; background-color: rgb(238, 238, 255);"
border="0" cellpadding="5" cellspacing="0">
<tbody>
<tr>
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.dsf.requestmonitor.Async2Plus2</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top; width: 10px;"><br>
</td>
<td style="vertical-align: top;"> <br>
</td>
</tr>
</tbody>
</table>
</div>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td style="text-align: left;"> <br>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<table
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204);"
border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td
style="text-align: left; background-color: rgb(255, 204, 204);"><span
style="text-decoration: underline;">Excercise abc</span>: xyz </td>
</tr>
</tbody>
</table>
<br>
<br>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -1,159 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>DSF Common Patterns</title>
</head>
<body>
<h2 style="text-align: center;">DSF Common Patterns<br>
</h2>
<h4>Summary</h4>
<h3>DSF</h3>
<ul>
<li>Customizing, componentization, performance.</li>
</ul>
<h3>Asynchronous Methods</h3>
One of the central features of DSF is that it relies very heavily on
the use of asynchronous methods.&nbsp; <span
style="font-style: italic;">Asynchronous methods</span> here mean
simply methods that <span style="font-weight: bold;">use a callback
object to indicate their completion</span>. The use of asynchronous
methods can be very contageous in a system, where if a lower level API
is composed of asynchronous methods, a higher level system which uses
those methods also has to have asynchronous methods in its interface
(or risk blocking its calling thread).<br>
<br>
TODO? : diagram of a layered system with asynchronous APIs<br>
<h4>Request Monitor</h4>
There is a standard callback object used in DSF, the request
monitor.&nbsp; A request monitor has the following features:<br>
<ul>
<li><span style="text-decoration: underline;">Executor</span> - A
argument to the request monitor constructor allows the user to specify
what executor should be used to invoke the callback method.&nbsp; <br>
</li>
<li><span style="text-decoration: underline;">Status</span> -
Asynchronous methods that take a callback can always set the status
indicating the success or failure of the call.</li>
<li><span style="text-decoration: underline;">Callback Methods</span>
- The request monitor declares several protected methods which are
invoked when the callback is invoked: handleCompleted(), handleOK(),
handleError(), etc.&nbsp; The users may override these methods as
needed to perform additional processing upon asynchronous method
completion.</li>
<li><span style="text-decoration: underline;">Parent Request Monitor</span>
- If the method calling an asynchronous method is itself asynchronous,
it may set its argument request monitor as the parent of the request
monitor it is creating.&nbsp; The parent request monitor will be <br>
automatically invoked when the lower level request monitor is completed.</li>
</ul>
Following is the snippet from a the "hello world" example of using a
request monitor:<br>
<pre><a name="line26"> 26: </a><strong><font color="#4169e1"><a
name="AsyncHelloWorld"></a>public class AsyncHelloWorld </font></strong>{<br><br><a
name="line28"> 28: </a><strong><font color="#4169e1"> public static void main(String[] args)</font></strong> {<br><a
name="line29"> 29: </a> Executor executor = ImmediateExecutor.getInstance();<br><a
name="line30"> 30: </a> RequestMonitor rm = new RequestMonitor(executor, null);<br><a
name="line31"> 31: </a> asyncHelloWorld(rm);<br><a name="line32"> 32: </a> }<br><br><a
name="line34"> 34: </a> static void asyncHelloWorld(RequestMonitor rm) {<br><a
name="line35"> 35: </a> System.out.println(<font color="#666666">"Hello world"</font>);<br><a
name="line36"> 36: </a> rm.done();<br><a name="line37"> 37: </a> }<br></pre>
<ul>
<li>Line 29 creates an "immediate executor".&nbsp; Unlike more
sophisticated executors, the immediate executor simply invokes the
runnable it receives immediately.&nbsp; It does not use any threads and
it will never throw a RejectedExecutionException.</li>
<li>Line 30 creates the request monitor.&nbsp; This program does not
perform any processing after the callback is invoked, so it does not
override RequestMonitor's completion methods.</li>
<li>Line 36 marks the callback as completed and implicilty invokes
the callback method.&nbsp; As a contract with the caller, the
asynchronous method has to invoke done() when its finished.&nbsp; As
there is no compiler support for ensuring that the asynchronous method
completes the request monitor,&nbsp; failure to do so results in common
but often suble and difficult to track down bugs.<br>
</li>
</ul>
<h4>Data Request Monitor</h4>
The base request monitor is useful for returning status of the
asynchronous method, but they do not have an option of returning a
value to the caller.&nbsp; DataRequestMonitor can be used for that
purpose. A simple example of using the data request monitor:<br>
<pre><a name="line22"> 22: </a><strong><font color="#4169e1"><a
name="Async2Plus2"></a>public class Async2Plus2 </font></strong>{<br><br><a
name="line24"> 24: </a><strong><font color="#4169e1"> public static void main(String[] args)</font></strong> {<br><a
name="line25"> 25: </a> Executor executor = ImmediateExecutor.getInstance();<br><a
name="line26"> 26: </a> DataRequestMonitor&lt;Integer&gt; rm = <br><a
name="line27"> 27: </a> new DataRequestMonitor&lt;Integer&gt;(executor, null) {<br><a
name="line28"> 28: </a> @Override<br><a name="line29"> 29: </a><strong><font
color="#4169e1"> protected void handleCompleted()</font></strong> {<br><a
name="line30"> 30: </a> System.out.println(<font
color="#666666">"2 + 2 = "</font> + getData());<br><a name="line31"> 31: </a> }<br><a
name="line32"> 32: </a> };<br><a name="line33"> 33: </a> asyncAdd(2, 2, rm);<br><a
name="line34"> 34: </a> }<br><br><a name="line36"> 36: </a> static void asyncAdd(int value1, int value2, DataRequestMonitor&lt;Integer&gt; rm) {<br><a
name="line37"> 37: </a> rm.setData(value1 + value2);<br><a
name="line38"> 38: </a> rm.done();<br><a name="line39"> 39: </a> }<br><a
name="line40"> 40: </a>}<br></pre>
<ul>
<li>Lines 26-27 create the data request monitor using a local class
declaraion.&nbsp; Note the type parameter to DataRequestMonitor allows
for compiler checking of the type when calling getData() and setData()
methods.</li>
<li>Lines 29-31 override the standard callback to print the result of
the calculation to the console.<br>
</li>
</ul>
<h4>Multi-Request Monitor</h4>
A common problem when using asynchronous is that several asynchronous
methods need to be called in parallel, so the calling method needs to
somehow manage the completion of several request monitors.&nbsp;
CountingRequestMonitor can be used for this purpose.&nbsp; It is
configured such that it's done() method needs to be called a <span
style="font-style: italic;">count</span> number of times before the
callback method is invoked.&nbsp; <br>
The following snipped from the AsyncQuicksort example shows a simple
example of using the CountingRequestMonitor:<br>
<pre><a name="line42"> 42: </a> static void asyncQuicksort(final int[] array, final int left, <br><a
name="line43"> 43: </a> final int right, RequestMonitor rm) <br><a
name="line44"> 44: </a> {<br><a name="line45"> 45: </a> <font
color="#4169e1">if</font> (right &gt; left) {<br><a name="line46"> 46: </a> int pivot = left;<br><a
name="line47"> 47: </a> int newPivot = partition(array, left, right, pivot); <br><a
name="line48"> 48: </a> printArray(array, left, right, newPivot);<br><a
name="line49"> 49: </a> <br><a name="line50"> 50: </a> CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);<br><a
name="line51"> 51: </a> asyncQuicksort(array, left, newPivot - 1, countingRm);<br><a
name="line52"> 52: </a> asyncQuicksort(array, newPivot + 1, right, countingRm);<br><a
name="line53"> 53: </a> countingRm.setDoneCount(2);<br><a
name="line54"> 54: </a> } <font color="#4169e1">else</font> {<br><a
name="line55"> 55: </a> rm.done();<br><a name="line56"> 56: </a> }<br><a
name="line57"> 57: </a> }<br></pre>
<ul>
<li>Line 50 creates the CountingRequestMonitor.&nbsp; Note that the
parent request monitor is set to the request monitor from the
asyncQuicksort() argument.&nbsp; This parent request monitor is
automatically called when the counting request monitor is completed.</li>
<li>Lines 51 and 52, use the same instance of counting request
monitor when calling the sub-routine.&nbsp; Each sub-routine will call
done() on the counting request monitor.</li>
<li>Line 53 sets the count to the number of sub-routines called with
the counting request monitor.&nbsp; Note that the done count can be set
after calling the sub-routines, because the counting request monitor
will not be completed until the count is set. <br>
</li>
<li>Line 55 Don't forget to complete the request monitor in all
execution paths!<br>
</li>
</ul>
<h3>Non-Executor Thread</h3>
<h4>Future</h4>
<h4>Query</h4>
<h4>Concurrency Annotations<br>
</h4>
<h3>Services</h3>
<h4>OSGi</h4>
<h4>Session</h4>
<h4>Tracker</h4>
<h3>Data Model</h3>
<h3>View Model</h3>
<h4>Adapter, Provider, Node</h4>
<h4>Timers</h4>
</body>
</html>