スレッド間通信飽きた


 何かここは速度要るもんらしいから、速度出るように頑張って書いてるんだけど飽きた。
 戻り値が欲しいとこなんて、演算要求投げてしばらく後に受け取り処理置いたり、とか8087臭がして扱いにくそうで困る。戻り値や引数の型をコンパイラが面倒見てくれないような世界に突っ込んでいいのかどうか。まー、やってしまえば問題無く書けるんだろうとは思うが。

 例のt2t_pipeは、pop()とpop_and_clear()を分けて、

  T pop () {
    assert( ! empty() );
    RMB();
    T result = buf_[index_to_pop_];
    index_to_pop_ = next_index_of( index_to_pop_ );
    WMB();
    return result;
  }
  T pop_and_clear () {
    assert( ! empty() );
    T result;
    RMB();
    { using namespace std;
      swap( result, buf_[index_to_pop_] );
    }
    index_to_pop_ = next_index_of( index_to_pop_ );
    WMB();
    return result;
  }

こんなんになった。PODなんかはpop()でいいし、shared_ptrみたいなのはpop_and_clear()で即削除させる感じ。クリアしたいかは色々な状況があるから、SFINAEで分けるのは無理。パイプクラス自体を二つ作る手もあるけど、まあこれでもいいだろ。
 出来れば、送信専用の関数は送信側にしか見えないような設計にしたいんだけど、思いつかなくてめんどくさいからしてない。デザインパターンとか勉強すりゃ出てくるのかなあ。まーいいか今はこれでも。
 これで大体完成なのかなあ。重くしたくないしなあ。呼び出し側がいちいち待機ループを組むのがめんどくさいが、バルク化する時は逆に楽そうな感じがする。
 リングバッファだからfull()なんかチェックしなきゃならないんだよ、って考え方もある。つまり標準のqueueかdeque辺りに突っ込めば、と。多分どうせスレッドセーフなコンテナではないから、full()が起きたらスレッドローカルなstd::queueに突っ込んでおく方式とかだな。
 うん。ボツだ(笑)。ぶっちゃけ、full()が起きるような状況になったら送信側はちょっと休んでろ。頻発するようなら共有パイプ小さすぎだろうし。アプリケーションによっては休み無く永久にpush()し続ける可能性もあるし。やっぱこのままでいいべ。

 んじゃ、t2t_pipe<int>でも作って、どう最適化されるか見てみようぜー。
 見てみた。大体ガチで削られてた。めでたしめでたし。t2t_pipe< shared_ptr<new T> >とかに比べたら雲泥のソレだな。
 だがメモリアクセスはそれなりに残るな…。別スレッドへの高速な通信ってメモリ以外無いよなあ。コア間のP2P通信レジスタとか無いですか。
 つーかそういう頑張るアプリ書いてる訳じゃないんだってのに俺は。まあ無駄なパズル遊びの癖は直らないんだろうなあ(笑)。


地震ヤバくね


 M6.9に続き、M6.6。静岡震度6弱とか。
 深いとこの地震が浅いとこの地震を誘発したり云々とか聞くと、何かそろそろ関東向けに溜まってるパワーも解放されそうで恐ろしいことであるなあ。
 二階建てはほとんど一階部分が潰れるらしいから、なるべく一階にはいたくないな(笑)。本番が来たら火の用心も大事そうだ。


newしすぎてうざい


 スレッドからスレッドに要求投げるんですよ。パケットサイズもたまーに可変な奴があって。
 呼び出し側スタックにパケットの実体を置いて、スレッド越しにポインタだけ投げていいなら一番コスト安いんだけどさ。受け取られるまでは送信側でスタック変数を生かしておく必要がありますね。論外ですね。
 んじゃ静的記憶だと、えーと、可変長のリクエストだから…。どうすんだ?

 ってとこで考えるのをやめてnewしまくった。しかもスレッド越しに渡すからshared_ptrで包んだ。リクエスト一個一個で毎回毎回shared_ptr<packet_base> packet_sp ( new packet_derived( arg1, arg2 ) )みたいな。さすがにイラッと来るものが。
 まあでも、リクエストの粒度が粗ければ大したことも無いか、とか思うようにしてたんだけどさ。割と細かく出来ないと厳しい気がしてきたんですよ。あんまり細かすぎてもスレッド増やす意味無くなるけど。つーか元々意味無いんじゃねーの(笑)。いや練習という大事な意味が(笑)。

 ということで真面目に考えた。
 …引数の受け渡し用のパイプを何本か作ればいいだけじゃね?
 一対一のパイプだからpush/popの順番が狂ったりも無いし。むしろ引数を遅延して渡せるのは便利な気もするな。メモリ効率はどうなんだろう。まーPC向けだから気にするレベルじゃないな。つーかnewしまくるよりはなあ。
 よーし早速書いてみよう。いや、やっぱ明日くらいにしよう(笑)。


素直にメモリバリア


 つーか別に普通に_ReadWriteBarrier()置いてasm吐かせて中見れば安心じゃん、と思ったのでそうした。asm出力変化なし。めでたしめでたし。
 というわけで、前のエントリのコードのとこにも_ReadWriteBarrier()を入れといた。

追記
 色々あってRMBとかWMBとかで誤魔化した。