
1 // 2 // Copyright (c) 2006, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 26 Dec 06 Brian Frank Stub 7 // 28 Jan 07 Brian Frank Implement threading model 8 // 9 10 ** 11 ** Thread models a thread of execution within a process. 12 ** See `docLang::Threading` for details. 13 ** 14 const class Thread 15 { 16 17 ////////////////////////////////////////////////////////////////////////// 18 // Construction 19 ////////////////////////////////////////////////////////////////////////// 20 21 ** 22 ** Make a new thread with the given name. If name is non-null then it 23 ** must not conflict with any threads currently active (new or running) 24 ** otherwise ArgErr is thrown. Convention is to use a dotted notation 25 ** beginning with your pod name to avoid naming collisions. If name is 26 ** null, then a unique name is automatically generated. If name is 27 ** non-null, then it must be valid according to `Uri.isName` otherwise 28 ** NameErr is thrown. 29 ** 30 ** If run is non-null, then it is invoked as the main loop of the thread. 31 ** If run is specified then it must be an immutable function (it cannot 32 ** capture state from the calling thread), otherwise NotImmutableErr is 33 ** thrown. If run is null, then you must subclass Thread and override 34 ** the run() method. The return value of run is available to the first 35 ** thread which calls `join`. 36 ** 37 ** The thread is created in the new state, and must be started using 38 ** the start method. 39 ** 40 new make(Str name := null, |Thread t->Obj| run := null) 41 42 ////////////////////////////////////////////////////////////////////////// 43 // Management 44 ////////////////////////////////////////////////////////////////////////// 45 46 ** 47 ** Lookup a thread in this VM by name. If the thread doesn't 48 ** exist and checked is false then return null, otherwise throw 49 ** UnknownThreadErr. Only active threads which are in the new 50 ** or running state may be found by name. 51 ** 52 static Thread find(Str name, Bool checked := true) 53 54 ** 55 ** Get the list of all active (new or running) threads 56 ** in the VM. 57 ** 58 static Thread[] list() 59 60 ** 61 ** Get the currently executing thread. Throw Err if 62 ** the current thread is not a proper Fan thread. 63 ** 64 static Thread current() 65 66 ** 67 ** Return the map of thread local variables. This is a map of "global" 68 ** variables visible only to the current thread. These variables are 69 ** keyed by a string name - by convention use a dotted notation beginning 70 ** with your pod name to avoid naming collisions. 71 ** 72 static Str:Obj locals() 73 74 ////////////////////////////////////////////////////////////////////////// 75 // Identity 76 ////////////////////////////////////////////////////////////////////////// 77 78 ** 79 ** Get the name of this thread which uniquely 80 ** identifies this thread within the VM. 81 ** 82 Str name() 83 84 ** 85 ** Print this thread's stack trace to the specified output 86 ** stream (or Sys.out by default). If this thread is not currently 87 ** running print nothing. 88 ** 89 Void trace(OutStream out := Sys.out) 90 91 ** 92 ** Return true if same thread according '===' same operator. 93 ** 94 override Bool equals(Obj obj) 95 96 ** 97 ** Return name.hash. 98 ** 99 override Int hash() 100 101 ** 102 ** Default toStr returns name. 103 ** 104 override Str toStr() 105 106 ////////////////////////////////////////////////////////////////////////// 107 // State 108 ////////////////////////////////////////////////////////////////////////// 109 110 ** 111 ** Return if this thread has been created, but not yet started. 112 ** 113 Bool isNew() 114 115 ** 116 ** Return if this thread has been started, but not yet stopped. 117 ** 118 Bool isRunning() 119 120 ** 121 ** Return if this thread has been stopped. 122 ** 123 Bool isDead() 124 125 ////////////////////////////////////////////////////////////////////////// 126 // Lifecycle 127 ////////////////////////////////////////////////////////////////////////// 128 129 ** 130 ** Start this thread running. If the thread is already 131 ** running or has been stopped, then throw Err. Return this. 132 ** 133 Thread start() 134 135 ** 136 ** Stop this thread from running. If this thread 137 ** is not currently running, then this method does nothing. 138 ** Note that the thread likely doesn't actually terminate 139 ** until it reaches an interruptable point in its main loop. 140 ** 141 Void stop() 142 143 ** 144 ** Wait for this thread to stop. If timeout is non-null, 145 ** then wait no longer then specified timeout. If this thread 146 ** hasn't been started yet, then throw Err. If this thread 147 ** is already dead, then this method is a no op. Return 148 ** the result of the run method for the first thread to join, 149 ** or null on subsequent calls. 150 ** 151 Obj join(Duration timeout := null) 152 153 ** 154 ** Put the currently executing thread to sleep for the 155 ** specified period. If the thread is interrupted for any 156 ** reason while sleeping, then InterruptedErr is thrown. 157 ** 158 static Void sleep(Duration duration) 159 160 ** 161 ** The run method implements the code to run in the thread. 162 ** If a run function was specified in the constructor, then it 163 ** is invoked, otherwise subclasses should override this method. 164 ** Threads which wish to process their message queue must 165 ** enter the main loop by calling the loop() method. The 166 ** return value of this method is available to the first thread 167 ** which calls the join method (the result is not required to 168 ** be immutable). 169 ** 170 protected virtual Obj run() 171 172 ** 173 ** Enter the message loop. This method does not return until 174 ** the thread is stopped. This receive callback is invoked by 175 ** the main loop each time a message is received from its send queue. 176 ** The callback should process the message and return a response. 177 ** If the calling thread is not this thread, then throw Err. 178 ** 179 ** If the the message was enqueued by sendAsync the response is 180 ** ignored; exceptions are printed to standard output and ignored. 181 ** 182 ** If the message was enqueued by sendSync the response is 183 ** returned to the caller and must be immutable or serializable; 184 ** exceptions are raised to the caller. 185 ** 186 Void loop(|Obj msg->Obj| receive) 187 188 ////////////////////////////////////////////////////////////////////////// 189 // Messaging 190 ////////////////////////////////////////////////////////////////////////// 191 192 ** 193 ** Enqueue the specified message for this thread, then 194 ** block the calling thread until this thread processes the 195 ** message via the loop() callback and return the result. 196 ** If the loop() callback throws an exception processing 197 ** the message, then that exception is raised to the calling 198 ** thread. If msg is not immutable or serializable, then IOErr 199 ** is thrown. If this thread is stopped while the caller is 200 ** blocked, then an InterruptedErr is thrown. Note that flow 201 ** control may block the caller until there is enough 202 ** space in this thread's message queue. 203 ** 204 Obj sendSync(Obj msg) 205 206 ** 207 ** Enqueue the specified message for this thread to process in 208 ** its received() callback. Using sendAsync() is fire-and-forget, 209 ** the caller has no guarantee that this thread will successfully 210 ** process the message. If msg is not immutable or serializable, 211 ** then IOErr is thrown. Note that flow control may block the 212 ** caller until there is enough space in this thread's message 213 ** queue. 214 ** 215 Void sendAsync(Obj msg) 216 217 }