スコープ内での生存戦略!
相変わらず更新頻度が低いけどまだちゃんと更新しますよ。
という訳で今回はC++のプログラムを組んでいる際に便利な機能を紹介します。
プログラムを打っているとスコープ内でのみ有効であってほしい処理が出てきます。
例えばマルチスレッドプログラム時のクリティカルセクションや処理負荷計測時の特定区間の計測処理。
例えばこんな処理です。
CriticalSection cs; // 同期オブジェクト
void Hoge(void)
{
cs.Enter(); // 同期オブジェクトの所有権を取得
~ 排他制御したい処理 ~
cs.Leave(); // 同期オブジェクトの所有権を破棄
}
この場合は最初と最後に排他制御の開始と終了処理を行えばいいだけです。
ただもしこの関数に途中で終了する処理があったとすれば次のようにしないといけません。
void Hoge(void)
{
cs.Enter();
if( 何らかの条件 )
{
cs.Leave();
return;
}
~ 排他制御したい処理 ~
cs.Leave();
}
これだと途中で終了する処理が増えるとどんどんLeaveの呼び出しが増えてめんどくさいし、奇麗なソースにもみえないですよね。
※そもそもコードが汚いとか言わないでね…
そんな場合には下記のようなクラスを経由するように書くとスコープ内での管理がすごく楽になります。
class ScopeLock
{
public:
ScopeLock(CriticalSection& cs)
: m_cs(cs)
{
m_cs.Enter();
}
~ScopeLock(void)
{
m_cs.Leave();
}
private:
CriticalSection& m_cs;
};
やっていることは単純です。
コンストラクタで同期オブジェクトを保持するようにしたうえで所有権を取得しています。
そして有効期限が切れてデストラクタが呼ばれると同期オブジェクトを破棄するようになっています。
それを使ってさっきの処理を書くとこんな感じです。
void Hoge(void)
{
ScopeLock lock(cs);
if( 何らかの条件 )
{
return;
}
~ 排他制御したい処理 ~
}
こうするとどこで処理が終了しようがスコープの有効期限が切れたタイミングで同期オブジェクトの所有権が破棄されるので細かいことを気にする必要なく実装することができます。
処理負荷や同期のタイミングは考える必要はありますがコード自体も見た目も格段に良くなるのでクリティカルセクション以外でも使える場面があれば凄く便利な仕組みなので是非お勧めします。