tracプラグインとか
なぜか大学院の授業でtracのプラグインを作ることになった。
とりあえずプラグインのtutorialを見てたら、プラグインが表示するHTML用テンプレートの記述に "include header.cs"みたいなのを発見。
csファイル*1ってなんだよと思って調べてみたらClearSilverの略だと判明。
http://discypus.jp/wiki/?%A5%BD%A5%D5%A5%C8/Bug%20Tracking/tracを見たところ、
- trac0.10 まではテンプレートエンジンとしてClearSilverを使ってる。ClearSilverはC言語で書かれている
- trac0.11からはPythonで書かれているGenshiをテンプレートエンジンとして使う
- ClearSilverがコンパイルできないような環境でもtracが使えるようにするため
- ただ、これまでのプラグインも動作させるため、trac0.11でもClearSilverは使えるらしい
ということらしい。
ClearSilverとGenshiの記述上の違いは以下のサイトが参考になりそう。
http://trac.edgewall.org/wiki/TracDev/PortingFromClearSilverToGenshi
株売買の準備
久しぶりに更新。
そろそろ株に手を出そうかと考えているので、株の売買補助ツールについて調べています。
ざっと探したところ、株価やチャート表示や、株価を条件に使った自動売買ツールはあるようですが、各株式会社に関連するニュースをチャートと対応づけるようなツールが見当たりませんでした*1。
株の勉強と遊びを兼ねて、自分でツールを作ろうと思います*2。
とりあえず株価情報を入手できないと話にならないので、Yahooファイナンスから株価情報を取り出して連想配列にして返すPHPコードを書きました。
で、この日記に添付しようと思ったら、はてな日記はテキストファイルの添付はできないみたいですね。日記本文に載せるには、ちょっと長いんだよな。
もうちょっと作ってからにどこかにアップするか。
*1:アメリカならGoogle Financeがありますね。日本の株式市場対応で同様の物を知っている人がいたら教えてください
*2:そのうち、Google Financeが日本市場に対応する気がするので、それほどツール作成に対する情熱はないですが・・・
ocamldebugの調査
ML言語の一種であるOcamlに付属している、ocamldebugというデバッガについて調べたのでメモ。
かなり間違っている可能性があるので、注意。
- gdbライクなCUI
- breakで停止できるのは、eventと呼ばれる箇所でのみ
- OcamlマニュアルのEventsの項目にeventとなる箇所が書いてある
- debuggerとdebugeeは別プロセス
- 日本語の処理関係は、まだ弱いらしい
- mlコード内のprint_int, print_string等の標準出力への出力用関数の処理は、ocamldebugでステップ実行している間は実際には行われない
- debugeeの実行が終了した段階で出力される
- 出力をバッファしてるのかな?
- おそらく、ファイル出力やTCP等によるデータ送信も同様
- タイムトラベル機能(後述)のためにこのような実装になってる?
- ファイルからの入力がどうなるかはまだ調べてない
- 変数の値等の状態も含めて実行を前の地点まで巻き戻して、そこから再実行する機能がある(タイムトラベル機能)
- ocamldebugが適切なタイミングでcheckpointを取り、それを利用して実行の巻き戻しを行う
- 巻き戻した地点がcheckpointを取った地点と一致しない場合は、最寄のcheckpointからその地点まで再実行して停止?
- checkpointを取るための実装にはforkを使ってる*2
- プロセスIDが巻き戻す前と後で違うなど、完全に状態を巻き戻すことはできないため、いやらしいプログラムの実行を巻き戻すと挙動がおかしくなった
ocamldebugはOcamlで実装されているので、私には読めん・・・
*1:http://caml.inria.fr/pub/docs/manual-ocaml.bak/manual030.htmlの16.7項に書かれているBNF記法を見る限りできないよなあ・・・たぶん
*2:http://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlのTurning reverse execution on and offの項目に書いてある
Debug.Traceを使ってprintf風デバッグ
Haskell処理系であるGHCにはDebug.Traceモジュールというのが提供されています*1。その中のtrace関数を使うと、C言語のおけるprintfデバッグのようなことができます。
ただ、Haskellは遅延評価を行う言語なので、traceが呼び出されるタイミングに注意する必要があるそうです。
以下、参考元サイト
- trace関数の使い方
- trace関数を使う際の注意点について
*1:http://www.haskell.org/ghc/docs/latest/html/libraries/base/Debug-Trace.html :traceの実装自体は難しくないそうなので、他の処理系でも同じようなモジュールがあるかもしれません
Haskellだってバグるよねっていう話し(C言語の関数をHaskellで呼ぶ)
C言語の関数をHaskellから呼び出すための記述に関する仕様が存在します*1
自分が使っているHaskell処理系のGHCは、この仕様に準拠しています。そこで、この機能を使ってバグったC関数をHaskellから呼ぶことでメモリアクセス違反させてみます*2。
// foo.c #include "HsFFI.h" static int mem; HsPtr wrong_ptr(int wrong) { if(wrong){ return (HsPtr)0xcfcfcfcf; }else{ return (HsPtr)&mem; } }
このwrong_ptr関数を呼ぶHaskellコードは以下、
-- main.hs import Foreign foreign import ccall "wrong_ptr" wrong_ptr :: Int -> IO (Ptr Int32) main = do ptr <- wrong_ptr 0 -- 変数memのアドレスがptrを束縛する pokeElemOff ptr 0 5 -- ptr[0] = 5 peekElemOff ptr 0 >>= print -- 5を出力 ptr <- wrong_ptr 1 -- 0xcfcfcfcfがptrを束縛する pokeElemOff ptr 0 100 -- メモリアクセス違反!!! peekElemOff ptr 0 >>= print
で、実際にやってみると、*3
> ghc foo.c main.hs -ffi -o foo > foo 5 <------ここで異常終了 >
この例はわざとらしいですが、Haskellのプログラムも、わかりにくいタイプのバグが入り込む余地があるっていうことがわかると思います。
C言語の関数を使わなきゃ良いっていう意見もあると思いますが、win32apiやらLinux等のシステムコールを直に扱いたい時には使わざる得ないでしょう*4。
また、絶対にC言語の関数を使わないっていうスタンスは、既存のライブラリを使ったほうが楽なのに、わざわざHaskellで書き直さなきゃいけないといった問題が発生する点でコストが高いと思います。
個人的には、デバッグ周辺のツールがもう少し充実しないと、普通のプログラムを書くのにHaskellを使う気になれません。上の例よりもっと複雑なコードがバグった時のデバッグ作業を考えると恐ろしすぎます。
GHC6.7からはデバッガが付属するそうなので、正式にリリースされたら使ってみようと思います。
Haskell本の感想とMonad
教養のために「ふつうのHaskellプログラミング」を読みました。Haskellを触ったことがない私のような人が読むのにちょうど良い本でした。
ただ、Monad則については読んでも良くわかりませんでした。Maybeモナド等、Monadインスタンスの使い方はわかるのですが、Monad則がどのようにして出てきて、どんな利点があるのか等の理論的な部分はページ量の関係か本に詳しく書いてありません。
そこで、Monadについて解説しているWebサイトを探して読んでみましたが、いまいち理解できてません。
ただ、IO処理等の副作用を持つ操作にMonadが利用できる理由については、以下のサイトを読むとなんとなくわかった気になれます。
スレッドの関数一覧(pthread, win32スレッド)
輪講でpthreadについて、ゼミ担当の人の話を聞きました*1。せっかくなので、windowsのスレッド用 apiと大体対応する関数を並べてみます。
なお、個々のスレッドをあらわすデータ構造の型は、pthreadではpthread_t, windowsスレッドではHANDLEです。各関数の機能詳細は、ググれば色んなサイトが出てくるのでそちらを見てください。
機能 | pthread関数名 | win32 スレッドapi名 |
スレッドの作成 | pthread_create | CreateThread, _beginthreadex*2 |
自スレッドの終了 | pthread_exit | ExitThread, _endthreadex*3 |
他スレッドを終了 | pthread_cancel | TerminateThread*4 |
スレッド終了時に自動的にスレッド作成時に確保したデータ(stack領域等)を解放するように指示 | pthread_detach | デフォルトでこの設定 |
他スレッドの終了を待つ | pthread_join | WaitForSingleObject, WaitForMultipleObjects |
使い終わったスレッドid(handle)を解放する | 解放する必要なし | CloseHandle |
現在実行中のスレッドのid(handle)を返す | pthread_self | GetCurrentThread |
mutexの作成 | pthread_mutex_init | CreateMutex |
mutexのロックを取る | pthread_mutex_lock | WaitForSingleObject |
mutexのロックを解除する | pthread_mutex_unlock | ReleaseMutex |
mutexの破棄 | pthread_mutex_destroy | CloseHandle |
スレッド固有の大域変数(TSD*5 or TLS*6 )を指す領域を確保 | pthread_key_create | TlsAlloc |
TSD(TLS)を指す領域を解放 | pthread_key_delete | TlsFree |
TSD(TLS)のアドレスを得る | pthread_getspecific | TlsGetValue |
TSD(TLS)のアドレスをセット | pthread_setspecific | TlsSetValue |
注意点
pthread_cancelで終了を要求されたスレッドは、その要求に抵抗することができます(pthread_setcancelstate関数でPTHREAD_CANCEL_DISABLEをセットする)。また、終了要求が実際に処理されるのは、要求を出されたスレッドでcancellation point(pause、waitシステムコールなど)を通過したときだけです。
これに対して、TerminateThreadで終了要求をだされたスレッドは、その要求に抵抗することができず、終了するタイミングもシステム依存になります。
また、pthread_cancelで終了したスレッドに対してpthread_joinしたり、あらかじめpthread_detachしていれば、終了したスレッド用のstack領域等が適切に解放されるのにたいして、TerminateThreadはstack領域が解放されません。Windowsがこのような実装になっているのは、実行中の他のスレッドがTerminateThreadで終了させられたスレッドのスタックを参照したときにメモリアクセス違反が起きるのを避けるためです*7。
追記
pthread_cancelを呼んだ後、呼ばれたスレッドを非同期に終了させる(cancellation pointを使わない)ようにすることもできます(pthread_setcanceltype関数)。ただ、この方法はTerminateThread同様に、あまり使うべきやりかたではないそうです。以下のブログで細かく説明されています。
http://d.hatena.ne.jp/yupo5656/20040724/p1