newLISP で On Lisp する...第21章(その2)

(この blog は、“short short story または 晴耕雨読な日々”からの引越してきたもの。スクリプトは、newLISP V10.2.1 以降で動作するように書き直しています。
defun 等の newLISP組込関数に無い関数は、特に断らない限り、newlisp-utility.lsponnewlisp.lsp に定義してあります。)

 今回は、第21章 マルチプロセス の動作例ですが、その前に前回紹介したコードの修正です。

(define *default-proc*
  (make-proc (state (fn (x)
                        (print "\n>>")
                        (print (eval-string (read-line) 'MAIN))
                        (pick-process)))))

 eval-string文 に、context シンボルのオプションを追加しています。何故かは、後ほど。

 手始めに、マクロforkx から 。前回紹介したコードを動かすには、2010/ 8/24版以降の onnewlisp.lspnewlisp-utility.lsp が必要です(i+ は newlisp-utility.lsp に、=defun は onnewlisp.lsp に定義してあります)。

> [cmd]
(=defun foo (x)
  (print "Foo was called with " x ".\n")
  (=values (i+ x)))
[/cmd]
(lambda (*cont* _x) 
 (letex ((x _x)) 
  (begin 
   (print "Foo was called with " x ".\n") 
   (=values (i+ x)))))
> (forkx (foo 2) 25)
(foo 2)
> *procs*
(gensym12)
> (proc-state gensym12)
(lambda (gensym11) (foo 2) (pick-process))
> (proc-pri gensym12)
25
> 

 *procs* に登録されたプロセスが gensym変数なのは、context版構造体の仕様です。 stateフィールドのラムダ式の最後に (pick-process) がありますから、継続してプロセスが実行されます。デフォルトのプロセス *default-proc* でも、最後に、pick-process を呼び出していますしね。
 次にマクロprogram を

> [cmd]
(program two-foos (a b)
  (forkx (foo a) 25)
  (forkx (foo b) 25)) 
[/cmd]
(lambda (*cont* _a _b) 
 (letex ((a _a) (b _b)) 
  (begin 
   (setq *procs* nil) 
   (begin 
    (forkx (foo a) 25) 
    (forkx (foo b) 25)) 
   (catch 
    (while true 
     (pick-process)) '*halt*) *halt*)))
> (two-foos 1 2)
Foo was called with 2.
Foo was called with 1.

>>(halt)
nil
> 

 優先順位が同じですから、後から追加されたプロセスから実行されます。
 しかし、優先順位を変えて実行すると、

> [cmd]
(program two-foos (a b)
  (forkx (foo a) 25)
  (forkx (foo b) 12)) 
[/cmd]
(lambda (*cont* _a _b) 
 (letex ((a _a) (b _b)) 
  (begin 
   (setq *procs* nil) 
   (begin 
    (forkx (foo a) 25) 
    (forkx (foo b) 12)) 
   (catch 
    (while true 
     (pick-process)) '*halt*) *halt*)))
> (two-foos 1 2)
Foo was called with 1.
Foo was called with 2.

>>(halt)
nil
> 

 優先度の高いプロセスから実行されます。
 ここで、先頭に >> がある行は、pick-process 中でデフォルトのプロセス *default-proc* が動作している状態です。そして、それは、multiple-value-bind 中で動作しています。ところで、multiple-value-bind は、multiple-value-bind の context で定義しています。つまり、デフォルトのプロセス *default-proc* の eval-string 文が multiple-value-bind の context で引数を評価してしまうのです。そのため、冒頭のスクリプト、eval-string が引数の文字列を評価する時に使う context を指定することにした訳です。普通の関数処理なら、問題ないのですが、、、
 さて、言い訳はこれくらいにして、次は、マクロwait の動作、 wait 式を1つ持つプロセス です。

> (define *open-doors* '())
()
> [cmd]
(=defun pedestrian ()
  (wait d (car *open-doors*)
    (print "\nEntering " (term d) ".\n")))
[/cmd]
(lambda (*cont*) 
 (letex () 
  (begin 
   (wait d (car *open-doors*) (print "\nEntering " (term d) ".\n")))))
> (program ped () (forkx (pedestrian) 1))
(lambda (*cont*) 
 (letex () 
  (begin 
   (setq *procs* nil) 
   (begin 
    (forkx (pedestrian) 1)) 
   (catch 
    (while true 
     (pick-process)) '*halt*) *halt*)))
> (ped)

>>(push 'door *open-doors*)
(MAIN:door)
Entering MAIN:door.

>>(halt)
nil
> 

 *open-doors* に要素が入るまで、本体のコードの実行が抑制されます。(MAIN:door) は、push の戻り値ですが、MAIN の context が付いてきているのは、前述の理由です。pedestrian で、format の代わりに使っている newLISP組込printterm を使い、出力から context 部分を取り除いています。

 予定外に長くなってきたので(汗)、黒板を使った同期 からは、次回に。

 以上、如何でしょうか?

広告

No comments yet

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。