001 package org.vishia.java2C.test;
002
003 /**This class demonstrates and tests the usage of threads with wait and notify.
004 * It implements the run()-Method of the Thread defined in the interface Runnable, which is inherited from the super class Thread.
005 * The class based on Thread, therefore no other instance is necessary to organize the thread.
006 * <br><br>
007 * The threads private data which should be able to access only by the current thread are stored
008 * in an extra class, here defined as static inner class.
009 *
010 */
011 public class TestWaitNotify extends Thread
012 {
013
014 /**This is a central thread-control variable. If it is set to false, the thread should finish. */
015 boolean shouldRun = true;
016
017 //TODO if this class is placed after TestThreadLocalData, a translation error occurs. Test!
018 /**This class is visible from outside, it is used from the notifying thread and from this thread,
019 * which waits for data.
020 *
021 */
022 public final static class WaitNotifyData
023 {
024 /**A value which is supplied with notify. */
025 int x;
026
027 /**Sequence counter to detect a notify. It is incremented on any notify(). */
028 int ctNewData;
029
030 /**Notify routine, it may be called from outside. New data are stored than. The <code>notify()</code>-call
031 * have to be placed in a <code>synchronized</code>- (mutex-)-block. Elsewhere in Java an exception is thrown.
032 * It is necessary to do so. That <code>synchronized</code>-block should be used to set the data,
033 * which are supplied with the notify action. Than the data and the notify-call are mutual exclusive handled.
034 * The Java-code is:
035 * <pre class="Java">
036 synchronized(this){
037 x = value;
038 ctNewData +=1;
039 notify();
040 }
041 * </pre>
042 * The value is stored. The sequence counter is incremented to advertise the notify. Than notify is called.
043 * All this operations are done under mutex in the <code>synchronized</code>-block.
044 * The translated C-code is:
045 * <pre class="CCode">
046 synchronized_ObjectJc(& ((* (ythis)).base.object)); {
047 ythis->x = value;
048 ythis->ctNewData += 1;
049 notify_ObjectJc(& ((* (ythis)).base.object), _thCxt);
050 } endSynchronized_ObjectJc(& ((* (ythis)).base.object));
051 * </pre>
052 * @param value The value supplied with notify.
053 */
054 public void notify(int value)
055 { synchronized(this){
056 x = value;
057 ctNewData +=1;
058 notify();
059 }
060 }
061 }
062
063
064
065
066 /**This class is defined only to use in the threads context. No other thread should have access to it.
067 * Therefore the instance can be defined in a thread-local data range. For Java2C it is possible
068 * to create a stack-instance.
069 * <br><br>
070 *
071 */
072 private final static class TestThreadLocalData
073 {
074 int x,y;
075
076 /**A sequence counter which holds the last value of {@link WaitNotifyData#ctNewData} to check
077 * whether all data are got.
078 *
079 */
080 int seqCtLast = -1, seqCt;
081
082 /**This counter is used to test whether the interrupting of the thread works. */
083 int testCtInterrupted = 0;
084
085 int testCtNothingReceived = 0;
086
087 int testCtSuccessNotify = 0;
088
089 int testCtMissNotify = 0;
090
091 /**Association to the data which are notifying from outside.
092 */
093 private final WaitNotifyData theAwaitingData;
094
095 TestThreadLocalData(WaitNotifyData theAwaitingDataP)
096 { this.theAwaitingData = theAwaitingDataP; ///
097 }
098
099 /**In this routine the thread is waiting for data. The thread runs only, if new data are available.
100 * But such an thread may be blocked forever, if no notifying occurs. Therefore it may be recommended,
101 * that the wait action is interrupted cyclically, to check some other conditions. In this case this
102 * routine waits max 1 second. If a notify doesn't occur, it returns anyway
103 * because outside there may be some other things to work.
104 * <br><br>
105 * The core of the routine is a wait for new data in Java written as:
106 * <pre class="Java">
107 synchronized(theAwaitingData){
108 if(seqCtLast == -1){
109 seqCt = seqCtLast = theAwaitingData.ctNewData;
110 }
111 theAwaitingData.wait(1000);
112 seqCt = theAwaitingData.ctNewData; //same as seqCtLast if no notify is called.
113 valueFromAwaitingData = theAwaitingData.x;
114 }
115 * </pre>
116 * This is translated to C in form:
117 * <pre class="CCode">
118 synchronized_ObjectJc(& ((* (REFJc(ythis->theAwaitingData))).base.object)); {
119 if(ythis->seqCtLast == -1)
120 {
121 ythis->seqCt = ythis->seqCtLast = REFJc(ythis->theAwaitingData)->ctNewData;
122 }
123 wait_ObjectJc(& ((*(REFJc(ythis->theAwaitingData))).base.object), 1000, _thCxt);
124 ythis->seqCt = REFJc(ythis->theAwaitingData)->ctNewData;
125 valueFromAwaitingData = REFJc(ythis->theAwaitingData)->x;
126 } endSynchronized_ObjectJc(& ((* (REFJc(ythis->theAwaitingData))).base.object));
127 * </pre>
128 * The rest of code tests the seqCt. If new data are available, the seqCt is incremented for 1.
129 * If a notify is missed, the counter is incremented for greater 1. If no notify is occured,
130 * but the wait time is out, the seqCt isn't incremented. This three conditions are tested,
131 * and the appropriate counters are counted. The counters give an overview of occurrence
132 * while running the process. Last not least the value given by notify is processed. But it is
133 * only an example.
134 */
135 private void awaitData()
136 {
137 int valueFromAwaitingData;
138 try {
139 synchronized(theAwaitingData){
140 if(seqCtLast == -1){
141 /**initial:*/
142 seqCt = seqCtLast = theAwaitingData.ctNewData;
143 }
144 /**Wait at maximum 1 second. */
145 theAwaitingData.wait(1000);
146 /**the thread is waken up either because notify or because time.*/
147 seqCt = theAwaitingData.ctNewData; //same as seqCtLast if no notify is called.
148 /**Copy the value to a stack variable, because after synchronized-end the value may be changed already.*/
149 valueFromAwaitingData = theAwaitingData.x;
150 }
151 }
152 catch(InterruptedException exc){
153 testCtInterrupted +=1;
154 valueFromAwaitingData = 0;
155 }
156 /**All data to process are stored in this instance, it is accessible only be the own thread. */
157 int seqCtDiff = seqCt - seqCtLast;
158 seqCtLast = seqCt;
159 if(seqCtDiff == 1){
160 /**The next data are received.*/
161 x += valueFromAwaitingData;
162 testCtSuccessNotify +=1;
163 }
164 else if(seqCtDiff == 0){
165 /**A wake up because time cycle has occurred ; */
166 testCtNothingReceived +=1;
167 }
168 else if(seqCtDiff > 0){
169 testCtMissNotify +=1;
170 }
171 else {
172 assert(false);
173 }
174 }
175
176
177
178 }
179
180
181 /**Aggregation to data to check wait/notify. */
182 final WaitNotifyData theAwaitingData;
183
184
185 /**Constructor.
186 * @param theAwaitingData for aggregation
187 */
188 TestWaitNotify(WaitNotifyData theAwaitingDataP)
189 { ////
190 this.theAwaitingData = theAwaitingDataP;
191 }
192
193
194 /**This routine overrides <code>Thread.start()</code>, it's a facade. It calls Thread.start() using
195 * <pre class=Java>
196 /**@java2c=stackSize(TestThreadLocalData+500). * /
197 super.start();
198 * </pre>
199 * It is a facade, containing the stacksize annotation regarded in Java2C-translation.
200 * The produced C-Code is:
201 * <pre clas=CCode>
202 start_ThreadJc(ythis, sizeof(TestWaitNotify_Test__TestThreadLocalData_s)+500, _thCxt);
203 * <pre>
204 * @see {@link java.lang.Thread#start()}
205 */
206 @Override public void start()
207 {
208 /**@java2c=stackSize(TestThreadLocalData+500). */
209 super.start();
210 }
211
212
213
214 /**This is the thread main-routine complying the Java rules. The routine is started
215 * if the ,,start(),,-method of this instance is called.
216 * <br><br>
217 * This routine creates an instances {@link TestThreadLocalData}, which are accessed by this thread only.
218 * In Java the instances are referenced, but the reference is only known in stack context,
219 * provided to called routines via parameter. In C the instances are allocated in the stack
220 * because a <code>@ java2c=stackInstance.</code> is written thereby. Large-size instances need
221 * an adequate stack size. The Java-code for this code-snippet is:
222 * <pre class="Java">
223 ...* @java2c=stackInstance. * /
224 TestThreadLocalData threadLocalData = new TestThreadLocalData();
225 * </pre>
226 * The generated C-code is:
227 * <pre class="CCode">
228 TestThread_Test__TestThreadLocalData_s threadLocalData;
229 ...
230 init_ObjectJc(&(threadLocalData.base.object), sizeof(threadLocalData), 0);
231 ctorO_TestThread_Test__TestThreadLocalData(&(threadLocalData.base.object), _thCxt);
232 * </pre>
233 * The thread contains a <code>while</code>-loop with test of {@link #shouldRun} and a sleep in the Java-form:
234 * <pre class="Java">
235 while(shouldRun){
236 threadLocalData.awaitData();
237 }//while
238 * </pre>
239 * In C it is mapped too, but it isn't used yet.
240 * <br><br>
241 * The C-code of this snippet is:
242 * <pre class="CCode">
243 while(ythis->shouldRun) {
244 awaitData_TestWaitNotify_Test__TestThreadLocalData_F(& (threadLocalData), _thCxt);
245 }
246 * </pre>
247 */
248 public void run(){
249 /**This instance is only visible in the threads context. It is allocated in the stack.
250 * @java2c=stackInstance. */
251 TestThreadLocalData threadLocalData = new TestThreadLocalData(theAwaitingData);
252 while(shouldRun){
253 threadLocalData.awaitData();
254 }//while
255 System.out.println("wait/notify-thread stopped at " + threadLocalData.x);
256 System.out.println("wait/notify-thread: nothingRcv=" + threadLocalData.testCtNothingReceived
257 + ", successfull=" + threadLocalData.testCtSuccessNotify
258 + ", missNotify=" + threadLocalData.testCtMissNotify
259 );
260 }
261
262
263
264 }