並列処理と排他の問題:rwlock
並列処理で一番性能に影響し、解決するのが難しいのが排他の問題です。あるデータを複数スレッドでアクセスする際に、mutexなどを使って排他すれば良さそうなものですが、どのくらいの粒度でロックをかけるかによって処理性能は大きく異なります。仕様面で工夫できるなら、排他せずに処理するのが性能面では最適ということも選択肢としてあります。
ある製品で、データのタイムアウトによる削除の関係で本来は排他をすべきところを、タイムアウトまでの時間を長くし、データアクセスと削除が同時に起きることはないような仕様で排他をせずに高速処理を実現しているものがありました。ところが、仕様を見直し、条件によってはできるだけ早くタイムアウト処理を行うということになり、見事に排他していないことによる不正メモリーアクセスが高負荷状態で発生するようになってしまいました。
mutexを使って排他してしまうと、削除以外に参照も排他してしまい、性能に大きな影響が出てしまうケースです。セマフォを使うかなぁ・・・でも、もっと良いものがあった気もするのだけど。。と悩んでいるときにメンバーの種田君から「ちょっと製品で相談をしたいのですが」と言われ「こっちは午前中のうちに難問を片づけないとならないから今日は無理!」と半分逆ギレっぽい感じに返答しながら、「せっかくだから、難問をどう解決するか、一緒に考えてよ」とミーティングスペースに連れだし、あれこれ作戦を出し合いました。「どれもいまいちだなぁ、単にこういう処理だけできれば良いんだけどねぇ」と言ったら「あぁ、それならrwlockが使えるのでは?」と言うことになり、「そうそう、それだ!」ということで、すぐに組み込んで動作確認し、大体良さそうなので、お昼過ぎにはパートナーさんのところに向かいました。
少し時間があったので、今日もガパオ。パッ・ガパオ・ムーサップ・カーオ・カイダーオ(豚挽肉のガパオ炒めライス目玉揚げ乗せ)です。ここのお店は昨日のお店と違いやや日本人向けの辛さですが、味はここも美味しいのですよねぇ。
さて、パートナーさんのところで、負荷テスト専用ハードを使い、超高負荷をかけると、実はまだまだ検討不足のところがあって直しましたが、基本的にrwlockでうまく動作し、性能低下もほとんど気にならないレベルでした。よかったよかった。。
なお、スレッド関連の動きを確認するときには、メモリーデバッグと同様、valgrindが使えます。メモリーの時にはvalgrind --tool=memcheckとやりますが、valgrind --tool=helgrindとすると、スレッドのレースコンディションとかの問題を指摘してくれます。もっとも、メモリーの時と同様、あえてやっているところも全部指摘されるので、かなりうるさくなるのと、処理速度もかなり低下します。