こんなデータ集計用のクラスがあります。
class Data{
long totalvalue {get; private set;}
long maxvalue {get; private set;}
long count {get; private set;}
void update(long value){
totalvalue += value;
count++;
if (maxvalue < value) maxvalue = value;
}
}
これをマルチスレッドで動かす事を考えます。
lockを使うのが簡単ですが、今回はlockより軽いInterlockedを使ってみます。
class Data{
long totalvalue {get; private set;}
long maxvalue {get; private set;}
long count {get; private set;}
void update(long value){
System.Threading.Interlocked.Add(ref totalvalue, value);
System.Threading.Interlocked.Increment(ref count)
if (maxvalue < value) maxvalue = value;
}
}
足し算とインクリメントは専用の関数があるのですが、最大値の更新は関数がありません。
使えそうな関数を探すと、「if (a == b) a = c;」という、同じ値なら値を更新する
CompareExchangeという関数がみつかります。
この関数を使い、比較前の値と異なる値になっていたら、もう一度やり直す、という仕組みをいれます。
class Data{
long totalvalue {get; private set;}
long maxvalue {get; private set;}
long count {get; private set;}
public static long InterlockedCompareExchange(ref long location, long value, Func<long, bool> compare)
{
long initialValue;
do
{
initialValue = location;
if (compare(initialValue)) return initialValue;
}
while (System.Threading.Interlocked.CompareExchange(ref location, value, initialValue) != initialValue);
return initialValue;
}
void update(long value){
System.Threading.Interlocked.Add(ref totalvalue, value);
System.Threading.Interlocked.Increment(ref count)
InterlockedCompareExchange(ref maxvalue, value, mv => mv < value);
}
}