チェンジセット 514
- コミット日時:
- 2008/05/26 22:58:22 (6 ヶ月前)
- ファイル:
-
- as3/Thread/branches/soumen/src/org/libspark/thread/Monitor.as (更新) (2 diffs)
- as3/Thread/branches/soumen/src/org/libspark/thread/Thread.as (更新) (10 diffs)
- as3/Thread/branches/soumen/src/org/libspark/thread/errors/CurrentThreadNotFoundError.as (追加)
- as3/Thread/branches/soumen/src/org/libspark/thread/errors/IllegalThreadStateError.as (追加)
凡例:
- 変更無し
- 追加
- 削除
- 更新
- コピー
- 移動
as3/Thread/branches/soumen/src/org/libspark/thread/Monitor.as
r509 r514 1 1 package org.libspark.thread 2 2 { 3 import flash.utils.Dictionary; 3 4 import org.libspark.thread.errors.InterruptError; 5 import flash.utils.setTimeout; 6 import flash.utils.clearTimeout; 4 7 5 8 public class Monitor implements IMonitor … … 7 10 public function Monitor() 8 11 { 9 _waitors = [];10 12 } 11 13 12 14 private var _waitors:Array; 15 private var _timeoutList:Dictionary; 16 17 private function getWaitors():Array 18 { 19 return _waitors || (_waitors = []); 20 } 21 22 private function registerTimeout(thread:Thread, timeout:uint):void 23 { 24 // マップがなければ生成 25 if (_timeoutList == null) { 26 _timeoutList = new Dictionary(); 27 } 28 29 // タイムアウトを設定して、thread をキーにして タイムアウトID を保存 30 _timeoutList[thread] = setTimeout(timeoutHandler, timeout, thread); 31 } 32 33 private function unregisterTimeout(thread:Thread):void 34 { 35 // マップがなければ何もしない 36 if (_timeoutList == null) { 37 return; 38 } 39 40 // thread をキーにして タイムアウトID を検索 41 var id:Object = _timeoutList[thread]; 42 43 // 見つかったらタイムアウトを解除する 44 if (id != null) { 45 clearTimeout(uint(id)); 46 delete _timeoutList[thread]; 47 } 48 } 13 49 14 50 public function wait(timeout:uint = 0):void 15 51 { 16 / *17 var thread:Thread = Thread. currentThread;52 // カレントスレッドを取得 53 var thread:Thread = Thread.getCurrentThread(); 18 54 19 if (thread.isSleeping || thread.isSuspending) { 20 throw new Error('Thread is already sleeping or suspending.'); 55 // スレッドに wait するよう依頼 56 thread.monitorWait(timeout != 0); 57 58 // 待機セットに並ばせる 59 getWaitors().push(thread); 60 61 // 待機時間が設定されている場合、タイムアウトハンドラを設定 62 if (timeout != 0) { 63 registerTimeout(thread, timeout); 21 64 } 22 23 thread.sleep(this);24 25 _waitors.push(thread);26 */27 65 } 28 66 29 67 public function notify():void 30 68 { 31 / *32 if (_waitors .length < 1) {69 // 待機しているスレッドがいなければ何もしない 70 if (_waitors == null || _waitors.length < 1) { 33 71 return; 34 72 } 35 73 74 // スレッドをひとつ取り出す 36 75 var thread:Thread = Thread(_waitors.shift()); 37 76 38 thread.wakeup(this); 39 */ 77 // タイムアウトを解除 78 unregisterTimeout(thread); 79 80 // スレッドを起こす 81 thread.monitorWakeup(); 40 82 } 41 83 42 84 public function notifyAll():void 43 85 { 44 / *45 if (_waitors .length < 1) {86 // 待機しているスレッドがいなければ何もしない 87 if (_waitors == null || _waitors.length < 1) { 46 88 return; 47 89 } 48 90 49 var waitors:Array = _waitors;50 var l:uint = waitors.length;91 // 例外保存用 92 var ex:Object = null; 51 93 52 for (var i:uint = 0; i < l; ++i) { 53 Thread(waitors[i]).wakeup(this); 94 // 全てのスレッドを起こす 95 for each (var thread:Thread in _waitors) { 96 97 // タイムアウトを解除 98 unregisterTimeout(thread); 99 100 // ここで try-catch を行うのは確実に全てのスレッドを起こすため 101 try { 102 thread.monitorWakeup(); 103 } 104 catch (e:Object) { 105 // 最初に起きた例外は保存 106 if (ex == null) { 107 ex = e; 108 } 109 } 54 110 } 55 111 56 waitors.length = 0; 57 */ 112 // 待機セットを空にする 113 _waitors.length = 0; 114 115 // 例外が発生していた場合は再スロー 116 if (ex != null) { 117 throw ex; 118 } 119 } 120 121 private function timeoutHandler(thread:Thread):void 122 { 123 // 既に待機セットが空になっていたら何もしない 124 if (_waitors == null || _waitors.length < 1) { 125 return; 126 } 127 128 // 待機セットから該当するスレッドを検索 129 var index:int = _waitors.indexOf(thread); 130 131 // 見つからなければ何もしない 132 if (index == -1) { 133 return; 134 } 135 136 // 待機セットから削除 137 _waitors.splice(index, 1); 138 139 // スレッドを起こす 140 thread.monitorTimeout(); 58 141 } 59 142 as3/Thread/branches/soumen/src/org/libspark/thread/Thread.as
r509 r514 2 2 { 3 3 import flash.events.IEventDispatcher; 4 import org.libspark.thread.errors.CurrentThreadNotFoundError; 5 import org.libspark.thread.errors.IllegalThreadStateError; 4 6 5 7 public class Thread extends Monitor … … 8 10 private static var _threadIndex:uint = 0; 9 11 private static var _currentThread:Thread = null; 12 private static var _toplevelThreads:Array = []; 10 13 11 14 /** … … 18 21 public static function initialize(executor:IThreadExecutor):void 19 22 { 20 _threadIndex = 0;23 //_threadIndex = 0; 21 24 _currentThread = null; 25 _toplevelThreads.length = 0; 22 26 23 27 // 古い IThreadExecutor の実行を止める … … 43 47 44 48 /** 49 * 現在実行中のスレッドを返します。 50 * ただし、現在実行中のスレッドがない(currentThread が null)の場合は CurrentThreadNotFoundError をスローします。 51 * 52 * @return 現在実行中のスレッド 53 * @throws org.libspark.thread.errors.CurrentThreadNotFoundError 現在実行中のスレッドがない場合 54 */ 55 internal static function getCurrentThread():Thread 56 { 57 var t:Thread = currentThread; 58 59 if (t != null) { 60 return t; 61 } 62 63 throw new CurrentThreadNotFoundError('Expected Thread.currentThread is not null, but actual null.'); 64 } 65 66 /** 45 67 * 全てのスレッドを実行します。通常、このメソッドは IThreadExector インターフェイスの実装クラスによって呼び出されます。 46 68 */ 47 69 public static function executeAllThreads():void 48 70 { 49 71 // 全てのトップレベルスレッドを呼び出す 72 var threads:Array = _toplevelThreads; 73 var l:uint = threads.length; 74 for (var i:uint = 0; i < l;) { 75 var thread:Thread = Thread(threads[i]); 76 if (!thread.execute()) { 77 // スレッドが終了した場合は削除 78 threads.splice(i, 1); 79 --l; 80 } 81 else { 82 ++i; 83 } 84 } 85 } 86 87 /** 88 * 指定されたスレッドをトップレベルスレッドとして追加します 89 * 90 * @param thread 追加するスレッド 91 */ 92 private static function addToplevelThread(thread:Thread):void 93 { 94 _toplevelThreads.push(thread); 95 } 96 97 /** 98 * 指定されたスレッドをトップレベルスレッドとして追加します 99 * 100 * @param threads 追加するスレッドの配列 101 */ 102 private static function addToplevelThreads(threads:Array):void 103 { 104 _toplevelThreads.push.apply(_toplevelThreads, threads); 50 105 } 51 106 … … 57 112 public static function next(func:Function):void 58 113 { 59 114 getCurrentThread()._runHandler = func; 60 115 } 61 116 … … 78 133 public static function timeout(func:Function):void 79 134 { 80 135 getCurrentThread()._timeoutHandler = func; 81 136 } 82 137 … … 111 166 _name = 'Thread' + _id; 112 167 _state = ThreadState.NEW; 168 _runningState = ThreadState.NEW; 169 _children = null; 170 _runHandler = null; 171 _timeoutHandler = null; 172 _joinMonitor = null; 113 173 } 114 174 … … 116 176 private var _name:String; 117 177 private var _state:uint; 178 private var _runningState:uint; 179 private var _children:Array; 180 private var _runHandler:Function; 181 private var _timeoutHandler:Function; 182 private var _joinMonitor:IMonitor; 118 183 119 184 public function get id():uint … … 144 209 public function start():void 145 210 { 146 211 // 既に実行されていたらエラー 212 if (_state != ThreadState.NEW) { 213 throw new IllegalThreadStateError('Thread is already running.'); 214 } 215 216 // state を実行フェーズに切り替える 217 _state = ThreadState.RUNNABLE; 218 _runningState = ThreadState.RUNNABLE; 219 220 // 次の実行関数を run に設定 221 _runHandler = run; 222 223 // カレントスレッドを取得 224 var current:Thread = currentThread; 225 226 if (current != null) { 227 // カレントスレッドがある(=別のスレッド内で start された)場合はそのスレッドの子となる 228 current.addChildThread(this); 229 } 230 else { 231 // カレントスレッドがない場合はトップレベルスレッドとなる 232 addToplevelThread(this); 233 } 234 } 235 236 internal function monitorWait(timeout:Boolean):void 237 { 238 // wait できる状態でなければエラー 239 if (_state != ThreadState.RUNNABLE && _state != ThreadState.TERMINATING) { 240 throw new IllegalThreadStateError('Thread can not wait.'); 241 } 242 243 // state を待機状態に切り替える 244 _state = timeout ? ThreadState.TIMED_WAITING : ThreadState.WAITING; 245 } 246 247 internal function monitorWakeup():void 248 { 249 // 待機状態でなければエラー 250 if (_state != ThreadState.WAITING && _state != ThreadState.TIMED_WAITING) { 251 throw new IllegalThreadStateError('Thread can not wakeup.'); 252 } 253 254 // state を実行状態に切り替える 255 _state = _runningState; 256 } 257 258 internal function monitorTimeout():void 259 { 260 // 待機時間付の待機状態でなければエラー 261 if (_state != ThreadState.TIMED_WAITING) { 262 throw new IllegalThreadStateError('Thread can not wakeup.'); 263 } 264 265 // state を実行状態に切り替える 266 _state = _runningState; 267 268 // 次に実行する実行関数をタイムアウト用のものに切り替える 269 if (_timeoutHandler != null) { 270 _runHandler = _timeoutHandler; 271 } 272 } 273 274 private function getJoinMonitor():IMonitor 275 { 276 return _joinMonitor || (_joinMonitor = new Monitor()); 147 277 } 148 278 149 279 public function join(timeout:uint = 0):Boolean 150 280 { 151 return false; 281 // 既に終了していたらそのまま帰る 282 if (_state == ThreadState.TERMINATED) { 283 return false; 284 } 285 286 // join 用のモニタで wait する 287 getJoinMonitor().wait(timeout); 288 289 return true; 152 290 } 153 291 … … 155 293 { 156 294 295 } 296 297 private function getChildren():Array 298 { 299 return _children || (_children = []); 300 } 301 302 private function addChildThread(thread:Thread):void 303 { 304 getChildren().push(thread); 305 } 306 307 private function execute():Boolean 308 { 309 // まだ start していなければ何もしない 310 if (_state == ThreadState.NEW) { 311 return true; 312 } 313 // 既に終了していれば何もしない 314 if (_state == ThreadState.TERMINATED) { 315 return false; 316 } 317 318 // すべての子スレッドを呼び出す 319 var children:Array = _children; 320 if (children != null) { 321 var cl:uint = children.length; 322 for (var ci:uint = 0; ci < cl; ) { 323 var child:Thread = Thread(children[ci]); 324 if (!child.execute()) { 325 // 終了したら削除 326 children.splice(ci, 1); 327 --cl; 328 } 329 else { 330 ++ci; 331 } 332 } 333 } 334 335 // 待機状態であればここでリターン 336 if (_state == ThreadState.WAITING || _state == ThreadState.TIMED_WAITING) { 337 return true; 338 } 339 340 // 今回実行する実行関数を保存 341 var runHandler:Function = _runHandler; 342 343 // ハンドラ郡の設定をクリア 344 _runHandler = null; 345 _timeoutHandler = null; 346 347 // Note: finalize の最後で wait が入って待機状態になった後に起きた等の場合に、 348 // runHandler が null の状態でここに到達することがある 349 if (runHandler != null) { 350 351 // カレントスレッドを設定 352 _currentThread = this; 353 354 try { 355 // 実行関数を呼び出す 356 runHandler.apply(this); 357 } 358 finally { 359 // カレントスレッドを元に戻す 360 _currentThread = null; 361 } 362 } 363 364 if (_runHandler != null) { 365 // 次に実行する実行関数が設定されている場合実行を継続 366 } 367 else { 368 // 次に実行する実行関数が設定されていない場合 369 if (_state == ThreadState.WAITING || _state == ThreadState.TIMED_WAITING) { 370 // 待機状態に入っている場合は次に繰り越す 371 } 372 else if (_runningState == ThreadState.TERMINATING) { 373 // 終了フェーズだった場合は実行を終了する 374 // 自分の子スレッドを、孤児スレッドとしてトップレベルに移動する 375 if (_children != null) { 376 addToplevelThreads(children); 377 // 子スレッドは破棄 378 _children = null; 379 } 380 // state を終了状態に切り替える 381 _state = ThreadState.TERMINATED; 382 _runningState = ThreadState.TERMINATED; 383 // join 用のモニタが存在(=join 待ちしているスレッドが存在)すれば notifyAll で起こす 384 if (_joinMonitor != null) { 385 _joinMonitor.notifyAll(); 386 _joinMonitor = null; 387 } 388 // 終了 389 return false; 390 } 391 else { 392 // 終了フェーズでない場合は終了フェーズに入る 393 // state を終了フェーズに切り替える 394 _state = ThreadState.TERMINATING; 395 _runningState = ThreadState.TERMINATING; 396 // 次の実行関数を finalize に設定 397 _runHandler = finalize; 398 } 399 } 400 401 return true; 157 402 } 158 403
