排他ロックは、ハッシュのエントリー毎に
ロック変数をハッシュのエントリー毎に確保して、エントリー毎ロックにしました。
ちょっとメモリーがもったいないですけど……
たとえばハッシュ手を取り出す関数
ロックしてる間に、hashValを参照して、e->Bestをコピー、ロックを外してからリターンする。
ハッシュ手が見つからない場合は、ロックを解除してからリターン
こんな感じですかね?
全体ロックだと、コア毎にロック変数が1個あれば、それをロックしておけばいいんですが、
ロックしてる間は、誰もハッシュテーブルを参照できなくなる。
エントリー毎にロックしておけば、同じエントリーを参照する人以外は、ロックの影響を受けません。
これってMySQLで言うところの、MyISAMエンジンとInnoDBの違いと似てますね
http://d.hatena.ne.jp/naoya/20060729/1154139996
MyISAM: Read は速いけどテーブルロックのため並行性が低い。運用が簡単。 InnoDB: MyISAM より Read は遅いけど並行性が高い 。行レベルロックなので。あとトランザクションや外部キー制約。運用が MyISAM よりちょっとめんどくさい。
MyISAMは全体ロック。InnoDBはエントリー毎のロックと近い。なぜInnoDBがreadが遅いんだろう?
逆にMyISAMのリードがロックを気にせずに好きに読んでるってことかな?
「Lock( &e->lock );」の部分のアドレス計算が、エントリーロックだと複雑になるのでInnoDBはreadが遅いのかもしれない。
最近の比較的大規模なWEBサービスは、InnoDBで運用すべきって考えが主流らしいです。
ブログサービスなんかは、90%以上はreadで、writeはほとんどないからMyISAMと考えがちなところを
実際は、
MyISAM で CPU に優しいシステムを選択するよりかは、マシンリソースを消費してでも並行性の高い InnoDB を選択するほうが、総体でのパフォーマンスは良かったりするんじゃないかなあという
とはてなのCEOのnaoyaさんが書かれてます。MixiもInnoDBを使ってるようです。
int Shogi::transMove_retrieve(Te& move) { // probe for(int i=0;i<DATASIZE;i++) { HashMove* e = &HashMoveTbl[i][ (hashVal) & HASHMASK ]; Lock( &e->lock ); if( e->hashVal == hashVal) { if( e->Best.to>=1+2*16 && e->Best.to<=9+10*16 ) { COPYTE(move,e->Best); UnLock( &e->lock ); return 1; } } UnLock( &e->lock ); } return 0; }