排他ロックは、ハッシュのエントリー毎に

ロック変数をハッシュのエントリー毎に確保して、エントリー毎ロックにしました。
ちょっとメモリーがもったいないですけど……


たとえばハッシュ手を取り出す関数
ロックしてる間に、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さんが書かれてます。MixiInnoDBを使ってるようです。

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;
}