Shammer's Philosophy

My private adversaria

Clozure CL で Thread を使ってみる【その1】

LISP で Queue を実装 version 1.0 - ShammerismでQueue を実装してみたので、それを使ってみたいと思う。Queue と言えば Consumer と Producer、つまり、Thread だ。Lisp での Thread はまだ不慣れなところが多いので、Queue の Consumer 処理と Producer 処理をうまく使いこなすのと同時に Thread も勉強してみる。まずは簡単にロックの作成とそのロックを取得したクリティカルセクションの実装。

ロックの作成

そのままズバリな function がある。その名も make-lock だ。これでロックを作成する。

? (defparameter *lock* (make-lock))
*LOCK*
?

クリティカルセクションの実装

with-lock-grabbed という Macro がある。これを使用すればよさそう。

(defmethod take-from-queue ((q queue))
  (do ()
      ((not *running*))
    (with-lock-grabbed (*lock*)
      (when (not (equal 0 (queue-count q)))
	(format t "Take client socket.~%")
	(let ((client (de-queue q)))
	  (do ()
	      ()
	    (let ((line (read-line client nil 'eof)))
	      (when (equal line 'eof) (return))
	      (format t "~A~%" line)))
	  (close-client-socket client))))))

全体の実装

メインの処理では、with-open-passive-socket ver 20120407 - Shammerismで実装した with-open-passive-socket を使用して、クライアントからの応答を待機。受け取ったSocketから文字を読み込み表示させる。まあ、EchoServer を Queue モデルで実装したという感じだろうか。上記2つと合わせた全体は以下のようになる。

(defparameter *running* t)

(defparameter *lock* (make-lock))

(defmethod take-from-queue ((q queue))
  (do ()
      ((not *running*))
    (with-lock-grabbed (*lock*)
      (when (not (equal 0 (queue-count q)))
	(format t "Take client socket.~%")
	(let ((client (de-queue q)))
	  (do ()
	      ()
	    (let ((line (read-line client nil 'eof)))
	      (when (equal line 'eof) (return))
	      (format t "~A~%" line)))
	  (close-client-socket client))))))

(let ((my-queue (create-queue)))
  (process-run-function "take" 'take-from-queue my-queue)
  (with-open-passive-socket (server "127.0.0.1" 7001)
    (let ((client (accept-client-socket server)))
      (format t "Enqueue Client socket.~%")
      (en-queue my-queue client)))
  (format t "finish.~%"))

これで動作させれば、nc 127.0.0.1 7001 で接続して任意の文字を送信できる。しかし、、、top で見ると CPU 使用率が 100% になる。wait の処理を入れていないからだろう。。。この点は改善しないといけない。