SML#のrefとCのptrに互換性が欲しい
Cのpthread_createとSML#でやりたいこと
SML#に多相型で安全なpthread_createを作りたいお話.
のはずだったんだけど,現状ぶち当たった問題点について.
もとのpthread_createは,
int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);
で,第3引数がスレッドとして実行する関数,第4引数がその引数になる.
SML#で素直にインポートすると以下のようになる.
type pthread_t = unit ptr val pthread_create = _import "pthread_create" : (pthread_t ref, unit ptr, unit ptr -> unit ptr, unit ptr) -> int
でもunit ptr*1とか使ってらんねーよwww
ということで以下のように使いたくなる.
val pthreadCreate : 'a::{only ptr prefix type}. ('a -> unit) -> 'a -> int
ってことをやってたんだけど,この実装のために
val ptr : 'a::{only ptr prefix type}. 'a -> 'a ptr
を作ろうとして詰まってる途中の話.
実装の方針とその結果として詰まったこと
- "fun pthreadCreate (f:'a->unit) (x:'a)"において,xをpthread_createで使えるようunit ptrになんとかキャストする関数を作る
- 同様に,fをpthread_createで使えるように"fn (arg:unit ptr) => f (Pointer.load (_cast(arg) : 'a ptr))"の関数とする.
- 多相なpthreadCreateでけたー!
そこでまずは値の参照を手に入れる.
そのためにref*2を_cast*3使ってptrへキャストすればいけると思ったんだけど.
# _cast(ref 1) : int ptr; val it = ptr : int ptr # Pointer.load (_cast(ref 1) : int ptr); val it = 1 : int # Pointer.load (_cast(ref 1) : int ptr); val it = 1 : int
お,いけそうかな?
# fun intPtr (x : int) = _cast(ref x) : int ptr; val intPtr = fn : int -> int ptr # val p = intPtr 1; val p = ptr : int ptr # Pointer.load p; val it = 3 : int # Pointer.load p; val it = 2147483647 : int # Pointer.load p; val it = ~1463444104 : int
ぐぬぬぬ.どういうことだ.
キャスト(ref→ptr)してロードしただけなのに,値が変化している.
ref x部を関数内にいれたことでGCされてるか何か?
なんにせよこれではうまくいかない.
別案を考えなくては….
追記
そもそも自分の理解が間違っていた._(:3」∠)_
ref xはxのコピーx'を作ってその参照を返す.
だから上記intPtrのコードの目的は「xの参照を得る」なのに,動作は計算途中に束縛したx'の参照が得られる.
しかもこのx'はどっかでGCされてしまう?
そこで以下のように予め参照値の領域を確保して,コピーx'の参照値の保存先とすれば,一応目的は達成できそう.
# fun intPtr (x : int) (res : int ref) = let val () = res := x in _cast (res) : int ptr end; val intPtr = fn : int -> int ref -> int ptr # val p = intPtr 1 (ref 0); val p = ptr : int ptr # Pointer.load p; val it = 1 : int # Pointer.load p; val it = 1 : int
これで行けるかな?
夕飯食ってから実装の続きをしよう.