static volatile BIO_METHODS *biom = NULL; static void init_biom(void) { biom = BIO_meth_new(BIO_TYPE_FD, "h2o_socket"); BIO_meth_set_write(biom, write_bio); BIO_meth_set_read(biom, read_bio); BIO_meth_set_puts(biom, puts_bio); BIO_meth_set_ctrl(biom, ctrl_bio); } static void setup_connection(...) { (いろいろ省略) // BIOを初期化 static pthread_once_t init_biom_once = PTHREAD_ONCE_INIT; pthread_once(&init_biom_once, init_biom); BIO *bio = BIO_new(biom); ... }
一方、pthread_onceを使う煩雑さを避けようとすると、自前でダブルチェックロックを書くことになるのですが、ダブルチェックロックをちゃんと書くのは難しい(参考:LCK10-J. ダブルチェックロック手法を誤用しない)し、実際間違えるし、毎回、間違えないように書こうとするのはストレスなんです。
というわけで、一念発起して、マクロを使って自分が本当にほしかった「once」を実装しました。
こんな感じで使います。
static void setup_connection(...) { (いろいろ省略) // BIOを初期化 static volatile BIO_METHODS *biom = NULL; H2O_MULTITHREAD_ONCE({ biom = BIO_meth_new(BIO_TYPE_FD, "h2o_socket"); BIO_meth_set_write(biom, write_bio); BIO_meth_set_read(biom, read_bio); BIO_meth_set_puts(biom, puts_bio); BIO_meth_set_ctrl(biom, ctrl_bio); }); BIO *bio = BIO_new(biom); ... }
グローバル変数やコールバック関数はなくなったし、初期化コードと利用コードが隣同士になって可読性が上がりました。
実際のコードは https://github.com/h2o/h2o/pull/2086 にありますので、ご参照ください。これで正しくダブルチェックロック実装できてるはず。
最後に一言。Cのマクロにブロック渡すのは超便利。
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.