チェンジセット 514

差分発生行の前後
無視リスト:
コミット日時:
2008/05/26 22:58:22 (6 ヶ月前)
コミッタ:
yossy
ログメッセージ:

Thread(soumen): 現時点でのテスト(20tests)をパスするように実装

ファイル:

凡例:

変更無し
追加
削除
更新
コピー
移動
  • as3/Thread/branches/soumen/src/org/libspark/thread/Monitor.as

    r509 r514  
    11package org.libspark.thread 
    22{ 
     3        import flash.utils.Dictionary; 
    34        import org.libspark.thread.errors.InterruptError; 
     5        import flash.utils.setTimeout; 
     6        import flash.utils.clearTimeout; 
    47 
    58        public class Monitor implements IMonitor 
     
    710                public function Monitor() 
    811                { 
    9                         _waitors = []; 
    1012                } 
    1113                 
    1214                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                } 
    1349                 
    1450                public function wait(timeout:uint = 0):void 
    1551                { 
    16                         /* 
    17                         var thread:Thread = Thread.currentThread
     52                        // カレントスレッドを取得 
     53                        var thread:Thread = Thread.getCurrentThread()
    1854                         
    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); 
    2164                        } 
    22                          
    23                         thread.sleep(this); 
    24                          
    25                         _waitors.push(thread); 
    26                         */ 
    2765                } 
    2866                 
    2967                public function notify():void 
    3068                { 
    31                         /* 
    32                         if (_waitors.length < 1) { 
     69                        // 待機しているスレッドがいなければ何もしない 
     70                        if (_waitors == null || _waitors.length < 1) { 
    3371                                return; 
    3472                        } 
    3573                         
     74                        // スレッドをひとつ取り出す 
    3675                        var thread:Thread = Thread(_waitors.shift()); 
    3776                         
    38                         thread.wakeup(this); 
    39                         */ 
     77                        // タイムアウトを解除 
     78                        unregisterTimeout(thread); 
     79                         
     80                        // スレッドを起こす 
     81                        thread.monitorWakeup(); 
    4082                } 
    4183                 
    4284                public function notifyAll():void 
    4385                { 
    44                         /* 
    45                         if (_waitors.length < 1) { 
     86                        // 待機しているスレッドがいなければ何もしない 
     87                        if (_waitors == null || _waitors.length < 1) { 
    4688                                return; 
    4789                        } 
    4890                         
    49                         var waitors:Array = _waitors; 
    50                         var l:uint = waitors.length
     91                        // 例外保存用 
     92                        var ex:Object = null
    5193                         
    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                                } 
    54110                        } 
    55111                         
    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(); 
    58141                } 
    59142                 
  • as3/Thread/branches/soumen/src/org/libspark/thread/Thread.as

    r509 r514  
    22{ 
    33        import flash.events.IEventDispatcher; 
     4        import org.libspark.thread.errors.CurrentThreadNotFoundError; 
     5        import org.libspark.thread.errors.IllegalThreadStateError; 
    46         
    57        public class Thread extends Monitor 
     
    810                private static var _threadIndex:uint = 0; 
    911                private static var _currentThread:Thread = null; 
     12                private static var _toplevelThreads:Array = []; 
    1013                 
    1114                /** 
     
    1821                public static function initialize(executor:IThreadExecutor):void 
    1922                { 
    20                         _threadIndex = 0; 
     23                        //_threadIndex = 0; 
    2124                        _currentThread = null; 
     25                        _toplevelThreads.length = 0; 
    2226                         
    2327                        // 古い IThreadExecutor の実行を止める 
     
    4347                 
    4448                /** 
     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                /** 
    4567                 * 全てのスレッドを実行します。通常、このメソッドは IThreadExector インターフェイスの実装クラスによって呼び出されます。 
    4668                 */ 
    4769                public static function executeAllThreads():void 
    4870                { 
    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); 
    50105                } 
    51106                 
     
    57112                public static function next(func:Function):void 
    58113                { 
    59                          
     114                        getCurrentThread()._runHandler = func; 
    60115                } 
    61116                 
     
    78133                public static function timeout(func:Function):void 
    79134                { 
    80                          
     135                        getCurrentThread()._timeoutHandler = func; 
    81136                } 
    82137                 
     
    111166                        _name = 'Thread' + _id; 
    112167                        _state = ThreadState.NEW; 
     168                        _runningState = ThreadState.NEW; 
     169                        _children = null; 
     170                        _runHandler = null; 
     171                        _timeoutHandler = null; 
     172                        _joinMonitor = null; 
    113173                } 
    114174                 
     
    116176                private var _name:String; 
    117177                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; 
    118183                 
    119184                public function get id():uint 
     
    144209                public function start():void 
    145210                { 
    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()); 
    147277                } 
    148278                 
    149279                public function join(timeout:uint = 0):Boolean 
    150280                { 
    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; 
    152290                } 
    153291                 
     
    155293                { 
    156294                         
     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; 
    157402                } 
    158403