Hatena::ブログ(Diary)

最強の食べ物はどう考えても天丼

2012-04-22

Gaucheでhash-setみたいなのを

作ってみたり。https://github.com/ayatoy/Gauche-hash-set

単にハッシュテーブルをラップしてるだけ。Clojureなんかと違って比較のタイプを指定できるので(ハッシュテーブルと同じ)、集合演算で違うタイプの集合を受け取ったらどちらの比較が使われるか注意が必要(タイプが違えば例外を投げるようにしても良いけど)。lset-*はO(n^2)かかったりするんで要素数が多い場合にはO(n)の方が良いということで。集合の数が多くて要素数が少ない時なんかはアロケーションのコストとか考えるとlsetの方が有利かもしれない。

2011-12-07

Gaucheのcontrol.jobで分からないこと

2011/12/31/ 新しいGaucheでは治ってます。

(ほとんど個人的なメモ)Gauche/lib/control/job.scmより。まず、job-waitの挙動。

(define (job-wait job :optional (timeout #f) (timeout-val #f))
  (let ([mutex (job-waiter-mutex job)]
        [cv (job-waiter-cv job)])
    (unless (and mutex cv) (error "job is not waitable" job))
    (let loop ()
      (mutex-lock! mutex)
      (let1 r (job-result job)
        (cond [(memq r '(done error killed)) (mutex-unlock! mutex) r]
              [(mutex-unlock! mutex cv timeout) (loop)]
              [else timeout-val])))))

これの (memq r '(done error killed)) の部分。resultの値でジョブの停止を判断してる。これだとthunkがdone error killedのどれかを返さないとスレッドがずっとブロックされちゃう気がする。(memq (job-status job) '(done error killed)) としなくて良いんだろうか。

もう一つ、job-run!とjob-mark-killed!で (condition-variable-broadcast! job) としてる部分。レコードをそのまま渡してるけど、cvを渡さなくて良いんだろうか。

そもそもcontrol.jobの役割をちゃんと把握してないのでなんとも言えないけど。

2011/12/9/1:58追記

ドキュメント読んだらjob-waitはstatusを返すんで、

@@ -69,8 +69,8 @@
     (unless (and mutex cv) (error "job is not waitable" job))
     (let loop ()
       (mutex-lock! mutex)
-      (let1 r (job-result job)
-        (cond [(memq r '(done error killed)) (mutex-unlock! mutex) r]
+      (let1 s (job-status job)
+        (cond [(memq s '(done error killed)) (mutex-unlock! mutex) s]
               [(mutex-unlock! mutex cv timeout) (loop)]
               [else timeout-val])))))
 
@@ -91,7 +91,7 @@
     (job-result-set! job result)
     (job-status-set! job status) ; no hazard. I'm the only writer.
     (if-let1 cv (job-waiter-cv job)
-      (condition-variable-broadcast! job)))
+      (condition-variable-broadcast! cv)))
   (job-status-set! job 'running)
   (job-touch! job :start)
   (guard (e [else (finish 'error e)])
@@ -105,4 +105,4 @@
   (job-result-set! job reason)
   (job-status-set! job 'killed)
   (if-let1 cv (job-waiter-cv job)
-    (condition-variable-broadcast! job)))
+    (condition-variable-broadcast! cv)))

な感じか。

2011-06-20

Gaucheで部分継続とdynamic-wind

部分継続とdynamic-windの動きを確認。

(use gauche.partcont)

(define (proc)
  (reset (shift k
           (dynamic-wind
               (lambda () (display "before,"))
               (lambda () (display "thunk,") (k))
               (lambda () (display "after,"))))
         (display "reset,")))

(proc)
before,thunk,after,reset,after,#<undef>

お?、resetしたらもう一回beforeが呼ばれるかと思ったけど違うのか。

で、もう一回

(proc)

ってやろうとすると

"vminsn.scm", line 1341: Assertion failed: SCM_PAIRP((vm)->handlers)
VM 0x1004c1c80 -----------------------------------------------------------
   pc: 00623fa8 (0000000e)
   sp: 0x1004c4020  base: 0x1004c4000  [0x1004c4000-0x1004d7880]
 argp: 0x1004c4020
 val0: #<undef>
 envs:
   0x1004c4008 #f
       up=0x100610850 size=1
       [ (#<undef>) ]
   0x100610850 #f
       up=0x100621ca8 size=2
       [ #<closure (proc #f #f #f)> #<closure (proc #f #f #f)> ]
   0x100621ca8 (proc #f #f)
       up=0x0 size=1
       [ #<closure (call/pc #f #f)> ]
conts:
   0x100610900
              env = 0x0
             argp = 0x100610930[0]
               pc = 0x1001b22d0 (00000000)
             base = 0x10061fd20
   0x10061daa0
              env = 0x0
...

みたいな難しいなにかが表示されてgoshが終了する。

2011-05-21

dynamic-windの動きを確認

一回脱出しいの戻ってきいの。

(let ((k #f)
      (s #t))
  (call/cc
   (lambda (cont)
     (dynamic-wind
         (lambda () (display "before,"))
         (lambda ()
           (display (call/cc (lambda (cont) (set! k cont) "thunk,")))
           (when s (cont)))
         (lambda () (display "after,")))))
  (when s
    (set! s #f)
    (k "thunk1,")))

before,thunk,after,before,thunk1,after,#<undef>

2011-05-20

Gaucheでデータベース接続するときのメモ

2011/5/20/9:58 ちょいとこの記事は問題あり(shiroさんから頂いたコメントを参照)詳しく理解できたらまた色々と書く

いままで、Gauche:CGI:スケジュール予定表:Shiro版 を参考にして、

...
(parameterize ((param (db-connect db)))
  (guard (e (else (dbi-close (param))
                  (raise e)))
    (begin0 (thunk)
            (dbi-close (param)))))
...

みないな感じで書いてたんだけど、これだとエラーの時はちゃんとdbi-closeされても、thunk内で他の継続を呼び出して脱出したときはdbi-closeされないっぽい(parameterizeはdynamic-windを使っているので他の継続を呼び出したときでもparamの値は元に戻る。コネクションオブジェクトをうっかり補足していなかったりすると、オブジェクトが回収されるまでデータベースに張り付いたままになる。)

で、確実にdbi-closeさせたい場合にはdynamic-windの方がいいかも。

...
(parameterize ((param (db-connect db)))
  (dynamic-wind
      (lambda ())
      thunk
      (lambda () (dbi-close (param)))))
...

クローズされないことを期待して脱出するなら話は別だけど。