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.