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